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

Increase balance #2446

Merged
merged 21 commits into from
Dec 15, 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
2 changes: 1 addition & 1 deletion cmd/blockchaincmd/add_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ func promptValidatorBalance(availableBalance uint64) (uint64, error) {
ux.Logger.PrintToUser("Validator's balance is used to pay for continuous fee to the P-Chain")
ux.Logger.PrintToUser("When this Balance reaches 0, the validator will be considered inactive and will no longer participate in validating the L1")
txt := "What balance would you like to assign to the validator (in AVAX)?"
return app.Prompt.CaptureValidatorBalance(txt, availableBalance)
return app.Prompt.CaptureValidatorBalance(txt, availableBalance, constants.BootstrapValidatorBalanceAVAX)
}

func CallAddValidator(
Expand Down
2 changes: 1 addition & 1 deletion cmd/validatorcmd/getBalance.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func getBalance(_ *cobra.Command, _ []string) error {
return err
}
}
ux.Logger.PrintToUser(" Validator Balance: %.5f", float64(balance)/float64(units.Avax))
ux.Logger.PrintToUser(" Validator Balance: %.5f AVAX", float64(balance)/float64(units.Avax))

return nil
}
163 changes: 163 additions & 0 deletions cmd/validatorcmd/increaseBalance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// Copyright (C) 2023, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package validatorcmd

import (
"fmt"

"github.com/ava-labs/avalanche-cli/pkg/constants"
"github.com/ava-labs/avalanche-cli/pkg/keychain"
"github.com/ava-labs/avalanche-cli/pkg/subnet"
"github.com/ava-labs/avalanche-cli/pkg/utils"

"github.com/ava-labs/avalanche-cli/pkg/cobrautils"
"github.com/ava-labs/avalanche-cli/pkg/networkoptions"
"github.com/ava-labs/avalanche-cli/pkg/txutils"
"github.com/ava-labs/avalanche-cli/pkg/ux"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/units"
"github.com/spf13/cobra"
)

var (
keyName string
useLedger bool
useEwoq bool
ledgerAddresses []string
balanceFlag float64
)

var increaseBalanceSupportedNetworkOptions = []networkoptions.NetworkOption{
networkoptions.Local,
networkoptions.Devnet,
networkoptions.EtnaDevnet,
networkoptions.Fuji,
networkoptions.Mainnet,
}

func NewIncreaseBalanceCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "increaseBalance",
Short: "Increase current balance of validator on P-Chain",
Long: `This command increases the validator P-Chain balance`,
RunE: increaseBalance,
Args: cobrautils.ExactArgs(0),
}

networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, increaseBalanceSupportedNetworkOptions)
cmd.Flags().StringVarP(&keyName, "key", "k", "", "select the key to use [fuji/devnet deploy only]")
cmd.Flags().StringVar(&l1, "l1", "", "name of L1 (to increase balance of bootstrap validators only)")
cmd.Flags().StringVar(&validationIDStr, "validation-id", "", "validationIDStr of the validator")
cmd.Flags().Float64Var(&balanceFlag, "balance", 0, "amount of AVAX to increase validator's balance by")
return cmd
}

func increaseBalance(_ *cobra.Command, _ []string) error {
network, err := networkoptions.GetNetworkFromCmdLineFlags(
app,
"",
globalNetworkFlags,
true,
false,
getBalanceSupportedNetworkOptions,
"",
)
if err != nil {
return err
}
var balance uint64
var validationID ids.ID
if validationIDStr != "" {
validationID, err = ids.FromString(validationIDStr)
if err != nil {
return err
}
} else {
isBootstrapValidator, err := app.Prompt.CaptureYesNo("Is the validator a bootstrap validator?")
if err != nil {
return err
}
if isBootstrapValidator {
if l1 == "" {
return fmt.Errorf("--l1 flag is required to get bootstrap validator balance")
}
sc, err := app.LoadSidecar(l1)
if err != nil {
return fmt.Errorf("failed to load sidecar: %w", err)
}
if !sc.Sovereign {
return fmt.Errorf("avalanche validator increaseBalance command is only applicable to sovereign L1s")
}
bootstrapValidators := sc.Networks[network.Name()].BootstrapValidators
if len(bootstrapValidators) == 0 {
return fmt.Errorf("this L1 does not have any bootstrap validators")
}
bootstrapValidatorsString := []string{}
bootstrapValidatorsToIndexMap := make(map[string]int)
for index, validator := range bootstrapValidators {
bootstrapValidatorsString = append(bootstrapValidatorsString, validator.NodeID)
bootstrapValidatorsToIndexMap[validator.NodeID] = index
}
chosenValidator, err := app.Prompt.CaptureList("Which bootstrap validator do you want to get balance of?", bootstrapValidatorsString)
if err != nil {
return err
}
validationID, err = ids.FromString(bootstrapValidators[bootstrapValidatorsToIndexMap[chosenValidator]].ValidationID)
if err != nil {
return err
}
} else {
validationID, err = app.Prompt.CaptureID("What is the validator's validationID?")
if err != nil {
return err
}
}
}
fee := network.GenesisParams().TxFeeConfig.StaticFeeConfig.TxFee
kc, err := keychain.GetKeychainFromCmdLineFlags(
app,
constants.PayTxsFeesMsg,
network,
keyName,
useEwoq,
useLedger,
ledgerAddresses,
fee,
)
if err != nil {
return err
}
deployer := subnet.NewPublicDeployer(app, kc, network)
if balanceFlag == 0 {
availableBalance, err := utils.GetNetworkBalance(kc.Addresses().List(), network.Endpoint)
if err != nil {
return err
}
balance, err = promptValidatorBalance(availableBalance / units.Avax)
if err != nil {
return err
}
} else {
balance = uint64(balanceFlag * float64(units.Avax))
}

_, err = deployer.IncreaseValidatorPChainBalance(validationID, balance)
if err != nil {
return err
}
deployer.CleanCacheWallet()
balance, err = txutils.GetValidatorPChainBalanceValidationID(network, validationID)
if err != nil {
return err
}
ux.Logger.PrintToUser(" New Validator Balance: %.5f AVAX", float64(balance)/float64(units.Avax))

return nil
}

func promptValidatorBalance(availableBalance uint64) (uint64, error) {
ux.Logger.PrintToUser("Validator's balance is used to pay for continuous fee to the P-Chain")
ux.Logger.PrintToUser("When this Balance reaches 0, the validator will be considered inactive and will no longer participate in validating the L1")
txt := "How many AVAX do you want to increase the balance of this validator by?"
return app.Prompt.CaptureValidatorBalance(txt, availableBalance, 0)
}
3 changes: 2 additions & 1 deletion cmd/validatorcmd/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ the validator will be considered inactive and will no longer participate in vali
app = injectedApp
// validator getBalance
cmd.AddCommand(NewGetBalanceCmd())

// validator increaseBalance
cmd.AddCommand(NewIncreaseBalanceCmd())
return cmd
}
28 changes: 14 additions & 14 deletions internal/mocks/prompter.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions pkg/prompts/prompts.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ type Prompter interface {
CaptureNodeID(promptStr string) (ids.NodeID, error)
CaptureID(promptStr string) (ids.ID, error)
CaptureWeight(promptStr string) (uint64, error)
CaptureValidatorBalance(promptStr string, availableBalance uint64) (uint64, error)
CaptureValidatorBalance(promptStr string, availableBalance uint64, minBalance float64) (uint64, error)
CapturePositiveInt(promptStr string, comparators []Comparator) (int, error)
CaptureInt(promptStr string, validator func(int) error) (int, error)
CaptureUint8(promptStr string) (uint8, error)
Expand Down Expand Up @@ -307,10 +307,11 @@ func (*realPrompter) CaptureNodeID(promptStr string) (ids.NodeID, error) {
func (*realPrompter) CaptureValidatorBalance(
promptStr string,
availableBalance uint64,
minBalance float64,
) (uint64, error) {
prompt := promptui.Prompt{
Label: promptStr,
Validate: validateValidatorBalanceFunc(availableBalance),
Validate: validateValidatorBalanceFunc(availableBalance, minBalance),
}
amountStr, err := prompt.Run()
if err != nil {
Expand Down
11 changes: 7 additions & 4 deletions pkg/prompts/validations.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,20 @@ func validateWeight(input string) error {
return nil
}

func validateValidatorBalanceFunc(availableBalance uint64) func(string) error {
func validateValidatorBalanceFunc(availableBalance uint64, minBalance float64) func(string) error {
return func(input string) error {
val, err := strconv.ParseFloat(input, 64)
if err != nil {
return err
}
if val < constants.BootstrapValidatorBalanceAVAX {
return fmt.Errorf("subnet validator balance must be at least 0.1 AVAX")
if val == 0 {
return fmt.Errorf("entered value has to be greater than 0 AVAX")
}
if val < minBalance {
return fmt.Errorf("validator balance must be at least %2f AVAX", minBalance)
}
if val > float64(availableBalance) {
return fmt.Errorf("current balance of %d is not sufficient for subnet validator balance to be %2f AVAX", availableBalance, val)
return fmt.Errorf("current balance of %d is not sufficient for validator balance to be %2f AVAX", availableBalance, val)
}
return nil
}
Expand Down
40 changes: 40 additions & 0 deletions pkg/subnet/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,30 @@ func (d *PublicDeployer) createSubnetTx(controlKeys []string, threshold uint32,
return d.Commit(&tx, true)
}

func (d *PublicDeployer) increaseValidatorPChainBalance(validationID ids.ID, balance uint64, wallet *primary.Wallet) (ids.ID, error) {
if d.kc.UsesLedger {
showLedgerSignatureMsg(d.kc.UsesLedger, d.kc.HasOnlyOneKey(), "IncreaseL1ValidatorBalance transaction")
}
unsignedTx, err := wallet.P().Builder().NewIncreaseL1ValidatorBalanceTx(
validationID,
balance,
)
if unsignedTx != nil {
if err := printFee("IncreaseL1ValidatorBalanceTx", wallet, unsignedTx); err != nil {
return ids.Empty, err
}
}
if err != nil {
return ids.Empty, fmt.Errorf("error building tx: %w", err)
}
tx := txs.Tx{Unsigned: unsignedTx}
if err := wallet.P().Signer().Sign(context.Background(), &tx); err != nil {
return ids.Empty, fmt.Errorf("error signing tx: %w", err)
}

return d.Commit(&tx, true)
}

func printFee(kind string, wallet *primary.Wallet, unsignedTx txs.UnsignedTx) error {
if showFees {
var pFeeCalculator avagofee.Calculator
Expand Down Expand Up @@ -1083,3 +1107,19 @@ func showLedgerSignatureMsg(
ux.Logger.PrintToUser("*** Please sign %s on the ledger device %s***", toSignDesc, multipleTimesMsg)
}
}

func (d *PublicDeployer) IncreaseValidatorPChainBalance(
validationID ids.ID,
balance uint64,
) (ids.ID, error) {
wallet, err := d.loadWallet()
if err != nil {
return ids.Empty, err
}
txID, err := d.increaseValidatorPChainBalance(validationID, balance, wallet)
if err != nil {
return ids.Empty, err
}
ux.Logger.PrintToUser("Validator balance has been increased with tx ID: %s", txID.String())
return txID, nil
}
Loading