Skip to content

Commit

Permalink
refactor(cmd): get first account address from wallet as reward address (
Browse files Browse the repository at this point in the history
#1594)

Co-authored-by: Javad Rajabzadeh <[email protected]>
  • Loading branch information
b00f and Ja7ad authored Nov 12, 2024
1 parent fd4129c commit a9f25bc
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 119 deletions.
110 changes: 56 additions & 54 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,21 +296,21 @@ func CreateNode(numValidators int, chain genesis.ChainType, workingDir string,
) ([]string, string, error) {
// To make process faster, we update the password after creating the addresses
walletPath := PactusDefaultWalletPath(workingDir)
walletInstance, err := wallet.Create(walletPath, mnemonic, "", chain)
wlt, err := wallet.Create(walletPath, mnemonic, "", chain)
if err != nil {
return nil, "", err
}

validatorAddrs := []string{}
for i := 0; i < numValidators; i++ {
addressInfo, err := walletInstance.NewValidatorAddress(fmt.Sprintf("Validator address %v", i+1))
addressInfo, err := wlt.NewValidatorAddress(fmt.Sprintf("Validator address %v", i+1))
if err != nil {
return nil, "", err
}
validatorAddrs = append(validatorAddrs, addressInfo.Address)
}

addressInfo, err := walletInstance.NewEd25519AccountAddress(
addressInfo, err := wlt.NewEd25519AccountAddress(
"Reward address", "")
if err != nil {
return nil, "", err
Expand Down Expand Up @@ -344,7 +344,7 @@ func CreateNode(numValidators int, chain genesis.ChainType, workingDir string,
if numValidators < 4 {
return nil, "", fmt.Errorf("LocalNeed needs at least 4 validators")
}
genDoc := makeLocalGenesis(*walletInstance)
genDoc := makeLocalGenesis(*wlt)
if err := genDoc.SaveToFile(genPath); err != nil {
return nil, "", err
}
Expand All @@ -355,11 +355,11 @@ func CreateNode(numValidators int, chain genesis.ChainType, workingDir string,
}
}

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

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

Expand All @@ -379,13 +379,13 @@ func StartNode(workingDir string, passwordFetcher func(*wallet.Wallet) (string,
}

defaultWalletPath := PactusDefaultWalletPath(workingDir)
walletInstance, err := wallet.Open(defaultWalletPath, true,
wlt, err := wallet.Open(defaultWalletPath, true,
wallet.WithCustomServers([]string{conf.GRPC.Listen}))
if err != nil {
return nil, nil, err
}

valAddrsInfo := walletInstance.AllValidatorAddresses()
valAddrsInfo := wlt.AllValidatorAddresses()
if len(valAddrsInfo) == 0 {
return nil, nil, fmt.Errorf("no validator addresses found in the wallet")
}
Expand All @@ -395,12 +395,12 @@ func StartNode(workingDir string, passwordFetcher func(*wallet.Wallet) (string,
valAddrsInfo = valAddrsInfo[:32]
}

rewardAddrs, err := MakeRewardAddresses(walletInstance, valAddrsInfo, conf.Node.RewardAddresses)
rewardAddrs, err := MakeRewardAddresses(wlt, valAddrsInfo, conf.Node.RewardAddresses)
if err != nil {
return nil, nil, err
}

valKeys, err := MakeValidatorKey(walletInstance, valAddrsInfo, passwordFetcher)
valKeys, err := MakeValidatorKey(wlt, valAddrsInfo, passwordFetcher)
if err != nil {
return nil, nil, err
}
Expand All @@ -415,7 +415,7 @@ func StartNode(workingDir string, passwordFetcher func(*wallet.Wallet) (string,
return nil, nil, err
}

return node, walletInstance, nil
return node, wlt, nil
}

// makeLocalGenesis makes genesis file for the local network.
Expand Down Expand Up @@ -547,61 +547,63 @@ func RecoverConfig(confPath string, defConf *config.Config, chainType genesis.Ch
return conf, err
}

func MakeRewardAddresses(walletInstance *wallet.Wallet,
valAddrsInfo []vault.AddressInfo, confRewardAddresses []string,
// MakeRewardAddresses generates a list of reward addresses based on wallet and configuration.
// If no reward addresses are provided in the config,
// the function attempts to use Ed25519 or BLS addresses from the wallet.
func MakeRewardAddresses(wlt *wallet.Wallet, valAddrsInfo []vault.AddressInfo,
confRewardAddrs []string,
) ([]crypto.Address, error) {
if len(confRewardAddresses) > 1 &&
len(confRewardAddresses) != len(valAddrsInfo) {
return nil, fmt.Errorf("reward addresses should be %v", len(valAddrsInfo))
}

// Create reward addresses
rewardAddrs := make([]crypto.Address, 0, len(valAddrsInfo))
if len(confRewardAddresses) != 0 {
for _, addrStr := range confRewardAddresses {
addr, _ := crypto.AddressFromString(addrStr)
rewardAddrs = append(rewardAddrs, addr)
}

if len(rewardAddrs) == 1 {
for i := 1; i < len(valAddrsInfo); i++ {
rewardAddrs = append(rewardAddrs, rewardAddrs[0])
}
}
} else {
for i := 0; i < len(valAddrsInfo); i++ {
valAddrPath, _ := addresspath.FromString(valAddrsInfo[i].Path)
accAddrPath := addresspath.NewPath(
valAddrPath.Purpose(),
valAddrPath.CoinType(),
switch {
// Case 1: No reward addresses in the config file.
case len(confRewardAddrs) == 0:
// Try to use the first Ed25519 address from the wallet as the reward address.
firstEd25519AddrPath := addresspath.NewPath(
vault.PurposeBIP44Hardened,
wlt.CoinType()+addresspath.HardenedKeyStart,
uint32(crypto.AddressTypeEd25519Account)+addresspath.HardenedKeyStart,
uint32(0)+addresspath.HardenedKeyStart)

addrInfo := wlt.AddressFromPath(firstEd25519AddrPath.String())
if addrInfo == nil {
// If no Ed25519 address is found, try the first BLS address instead.
firstBLSAddrPath := addresspath.NewPath(
vault.PurposeBLS12381Hardened,
wlt.CoinType()+addresspath.HardenedKeyStart,
uint32(crypto.AddressTypeBLSAccount)+addresspath.HardenedKeyStart,
valAddrPath.AddressIndex())
uint32(0))

addrInfo = wlt.AddressFromPath(firstBLSAddrPath.String())

addrInfo := walletInstance.AddressFromPath(accAddrPath.String())
if addrInfo == nil {
accAddrPath = addresspath.NewPath(
vault.PurposeBIP44Hardened,
valAddrPath.CoinType(),
uint32(crypto.AddressTypeEd25519Account)+addresspath.HardenedKeyStart,
uint32(0)+addresspath.HardenedKeyStart)

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

addr, _ := crypto.AddressFromString(addrInfo.Address)
addr, _ := crypto.AddressFromString(addrInfo.Address)
for i := 0; i < len(valAddrsInfo); i++ {
rewardAddrs = append(rewardAddrs, addr)
}
}

// Check if reward addresses are account address
for _, addr := range rewardAddrs {
if !addr.IsAccountAddress() {
return nil, fmt.Errorf("reward address is not an account address: %s", addr)
// Case 2: One reward address is specified in the config file.
case len(confRewardAddrs) == 1:
// Use this single address for all validators.
addr, _ := crypto.AddressFromString(confRewardAddrs[0])
for i := 0; i < len(valAddrsInfo); i++ {
rewardAddrs = append(rewardAddrs, addr)
}

// Case 3: Each validator has a corresponding reward address in the config file.
case len(confRewardAddrs) == len(valAddrsInfo):
for i := 0; i < len(valAddrsInfo); i++ {
addr, _ := crypto.AddressFromString(confRewardAddrs[i])
rewardAddrs = append(rewardAddrs, addr)
}

default:
return nil, fmt.Errorf("expected %v reward addresses, but got %v",
len(valAddrsInfo), len(confRewardAddrs))
}

return rewardAddrs, nil
Expand Down
163 changes: 98 additions & 65 deletions cmd/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,71 +223,104 @@ func TestPathsWindows(t *testing.T) {
func TestMakeRewardAddresses(t *testing.T) {
ts := testsuite.NewTestSuite(t)

walletPath := util.TempFilePath()
mnemonic, _ := wallet.GenerateMnemonic(128)
walletInstance, err := wallet.Create(walletPath, mnemonic, "", genesis.Mainnet)
assert.NoError(t, err)

_, _ = walletInstance.NewValidatorAddress("")
_, _ = walletInstance.NewValidatorAddress("")
_, _ = walletInstance.NewValidatorAddress("")

// Test 1 - Wallet without reward addresses
valAddrsInfo := walletInstance.AllValidatorAddresses()
confRewardAddresses := []string{}
_, err = MakeRewardAddresses(walletInstance, valAddrsInfo, confRewardAddresses)
assert.ErrorContains(t, err, "unable to find reward address for")

// Test 2 - Not enough reward addresses in wallet
rewardAddr1Info, _ := walletInstance.NewBLSAccountAddress("")
rewardAddr2Info, _ := walletInstance.NewBLSAccountAddress("")

_, err = MakeRewardAddresses(walletInstance, valAddrsInfo, confRewardAddresses)
assert.ErrorContains(t, err, "unable to find reward address for")

// Test 3 - Get reward addresses from wallet
rewardAddr3Info, _ := walletInstance.NewBLSAccountAddress("")

rewardAddrs, err := MakeRewardAddresses(walletInstance, valAddrsInfo, confRewardAddresses)
assert.NoError(t, err)
assert.Equal(t, rewardAddrs[0].String(), rewardAddr1Info.Address)
assert.Equal(t, rewardAddrs[1].String(), rewardAddr2Info.Address)
assert.Equal(t, rewardAddrs[2].String(), rewardAddr3Info.Address)

// Test 4 - Not enough reward addresses in config
confRewardAddr1 := ts.RandAccAddress().String()
confRewardAddr2 := ts.RandAccAddress().String()
confRewardAddresses = []string{confRewardAddr1, confRewardAddr2}

_, err = MakeRewardAddresses(walletInstance, valAddrsInfo, confRewardAddresses)
assert.ErrorContains(t, err, "reward addresses should be 3")

// Test 5 - Get reward addresses from config
confRewardAddr3 := ts.RandAccAddress().String()
confRewardAddresses = []string{confRewardAddr1, confRewardAddr2, confRewardAddr3}

rewardAddrs, err = MakeRewardAddresses(walletInstance, valAddrsInfo, confRewardAddresses)
assert.NoError(t, err)
assert.Equal(t, rewardAddrs[0].String(), confRewardAddr1)
assert.Equal(t, rewardAddrs[1].String(), confRewardAddr2)
assert.Equal(t, rewardAddrs[2].String(), confRewardAddr3)

// Test 6 - Set one reward addresses in config
confRewardAddr := ts.RandAccAddress().String()
confRewardAddresses = []string{confRewardAddr}

rewardAddrs, err = MakeRewardAddresses(walletInstance, valAddrsInfo, confRewardAddresses)
assert.NoError(t, err)
assert.Equal(t, rewardAddrs[0].String(), confRewardAddr)
assert.Equal(t, rewardAddrs[1].String(), confRewardAddr)
assert.Equal(t, rewardAddrs[2].String(), confRewardAddr)

// Test 7 - Set validator address as reward addresses in config
confRewardAddr = ts.RandValAddress().String()
confRewardAddresses = []string{confRewardAddr}

_, err = MakeRewardAddresses(walletInstance, valAddrsInfo, confRewardAddresses)
assert.ErrorContains(t, err, "reward address is not an account address")
setupWallet := func() *wallet.Wallet {
walletPath := util.TempFilePath()
mnemonic, _ := wallet.GenerateMnemonic(128)
wlt, err := wallet.Create(walletPath, mnemonic, "", genesis.Mainnet)
assert.NoError(t, err)

_, _ = wlt.NewValidatorAddress("Validator 1")
_, _ = wlt.NewValidatorAddress("Validator 2")
_, _ = wlt.NewValidatorAddress("Validator 3")

return wlt
}

t.Run("No reward addresses in wallet", func(t *testing.T) {
wlt := setupWallet()

valAddrsInfo := wlt.AllValidatorAddresses()
confRewardAddresses := []string{}
_, err := MakeRewardAddresses(wlt, valAddrsInfo, confRewardAddresses)
assert.ErrorContains(t, err, "unable to find a reward address in the wallet")
})

t.Run("Wallet with one Ed25519 address", func(t *testing.T) {
wlt := setupWallet()

addr1Info, _ := wlt.NewEd25519AccountAddress("", "")
_, _ = wlt.NewEd25519AccountAddress("", "")
_, _ = wlt.NewBLSAccountAddress("")

valAddrsInfo := wlt.AllValidatorAddresses()
confRewardAddresses := []string{}
rewardAddrs, err := MakeRewardAddresses(wlt, valAddrsInfo, confRewardAddresses)
assert.NoError(t, err)

assert.Equal(t, rewardAddrs[0].String(), addr1Info.Address)
assert.Equal(t, rewardAddrs[1].String(), addr1Info.Address)
assert.Equal(t, rewardAddrs[2].String(), addr1Info.Address)
})

t.Run("Wallet with one BLS address", func(t *testing.T) {
wlt := setupWallet()

addr1Info, _ := wlt.NewBLSAccountAddress("")
_, _ = wlt.NewBLSAccountAddress("")

valAddrsInfo := wlt.AllValidatorAddresses()
confRewardAddresses := []string{}
rewardAddrs, err := MakeRewardAddresses(wlt, valAddrsInfo, confRewardAddresses)
assert.NoError(t, err)

assert.Equal(t, rewardAddrs[0].String(), addr1Info.Address)
assert.Equal(t, rewardAddrs[1].String(), addr1Info.Address)
assert.Equal(t, rewardAddrs[2].String(), addr1Info.Address)
})

t.Run("One reward address in config", func(t *testing.T) {
wlt := setupWallet()

valAddrsInfo := wlt.AllValidatorAddresses()
confRewardAddresses := []string{
ts.RandAccAddress().String(),
}
rewardAddrs, err := MakeRewardAddresses(wlt, valAddrsInfo, confRewardAddresses)
assert.NoError(t, err)

assert.Equal(t, rewardAddrs[0].String(), confRewardAddresses[0])
assert.Equal(t, rewardAddrs[1].String(), confRewardAddresses[0])
assert.Equal(t, rewardAddrs[2].String(), confRewardAddresses[0])
})

t.Run("Three reward addresses in config", func(t *testing.T) {
wlt := setupWallet()

valAddrsInfo := wlt.AllValidatorAddresses()
confRewardAddresses := []string{
ts.RandAccAddress().String(),
ts.RandAccAddress().String(),
ts.RandAccAddress().String(),
}
rewardAddrs, err := MakeRewardAddresses(wlt, valAddrsInfo, confRewardAddresses)
assert.NoError(t, err)

assert.Equal(t, rewardAddrs[0].String(), confRewardAddresses[0])
assert.Equal(t, rewardAddrs[1].String(), confRewardAddresses[1])
assert.Equal(t, rewardAddrs[2].String(), confRewardAddresses[2])
})

t.Run("Insufficient reward addresses in config", func(t *testing.T) {
wlt := setupWallet()

valAddrsInfo := wlt.AllValidatorAddresses()
confRewardAddresses := []string{
ts.RandAccAddress().String(),
ts.RandAccAddress().String(),
}
_, err := MakeRewardAddresses(wlt, valAddrsInfo, confRewardAddresses)
assert.ErrorContains(t, err, "expected 3 reward addresses, but got 2")
})
}

func TestCreateNode(t *testing.T) {
Expand Down
4 changes: 4 additions & 0 deletions wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ func (w *Wallet) Name() string {
return path.Base(w.path)
}

func (w *Wallet) CoinType() uint32 {
return w.store.Vault.CoinType
}

func (w *Wallet) IsOffline() bool {
return len(w.grpcClient.servers) == 0
}
Expand Down
7 changes: 7 additions & 0 deletions wallet/wallet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -646,3 +646,10 @@ func TestTotalStake(t *testing.T) {

require.Equal(t, stake, val1.Stake()+val2.Stake())
}

func TestCoinType(t *testing.T) {
td := setup(t)
defer td.Close()

assert.Equal(t, td.wallet.CoinType(), uint32(21888))
}

0 comments on commit a9f25bc

Please sign in to comment.