Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(cmd): get first account address from wallet as reward address #1594

Merged
merged 3 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
) ([]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 @@
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 @@
}
}

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 @@
}

defaultWalletPath := PactusDefaultWalletPath(workingDir)
walletInstance, err := wallet.Open(defaultWalletPath, true,
wlt, err := wallet.Open(defaultWalletPath, true,

Check warning on line 382 in cmd/cmd.go

View check run for this annotation

Codecov / codecov/patch

cmd/cmd.go#L382

Added line #L382 was not covered by tests
wallet.WithCustomServers([]string{conf.GRPC.Listen}))
if err != nil {
return nil, nil, err
}

valAddrsInfo := walletInstance.AllValidatorAddresses()
valAddrsInfo := wlt.AllValidatorAddresses()

Check warning on line 388 in cmd/cmd.go

View check run for this annotation

Codecov / codecov/patch

cmd/cmd.go#L388

Added line #L388 was not covered by tests
if len(valAddrsInfo) == 0 {
return nil, nil, fmt.Errorf("no validator addresses found in the wallet")
}
Expand All @@ -395,12 +395,12 @@
valAddrsInfo = valAddrsInfo[:32]
}

rewardAddrs, err := MakeRewardAddresses(walletInstance, valAddrsInfo, conf.Node.RewardAddresses)
rewardAddrs, err := MakeRewardAddresses(wlt, valAddrsInfo, conf.Node.RewardAddresses)

Check warning on line 398 in cmd/cmd.go

View check run for this annotation

Codecov / codecov/patch

cmd/cmd.go#L398

Added line #L398 was not covered by tests
if err != nil {
return nil, nil, err
}

valKeys, err := MakeValidatorKey(walletInstance, valAddrsInfo, passwordFetcher)
valKeys, err := MakeValidatorKey(wlt, valAddrsInfo, passwordFetcher)

Check warning on line 403 in cmd/cmd.go

View check run for this annotation

Codecov / codecov/patch

cmd/cmd.go#L403

Added line #L403 was not covered by tests
if err != nil {
return nil, nil, err
}
Expand All @@ -415,7 +415,7 @@
return nil, nil, err
}

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

Check warning on line 418 in cmd/cmd.go

View check run for this annotation

Codecov / codecov/patch

cmd/cmd.go#L418

Added line #L418 was not covered by tests
}

// makeLocalGenesis makes genesis file for the local network.
Expand Down Expand Up @@ -547,61 +547,63 @@
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 {
Ja7ad marked this conversation as resolved.
Show resolved Hide resolved
// 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])
b00f marked this conversation as resolved.
Show resolved Hide resolved
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))
}
Loading