From 971693f0b86fb101813241468550713acd5a7d97 Mon Sep 17 00:00:00 2001 From: felipemadero Date: Tue, 8 Oct 2024 16:31:03 -0300 Subject: [PATCH] add poa setup to blockchain deploy (#2219) * add setup poa to blockchain deploy * add command * add proposervm update * proposervm flag for nodes * nit * nit * fixed dynamic fees params calculation * only adding tracked apis to apis in sidecar * improve prompts * fixing various stuff * add upgrade file * use anr etna enabled * keep upgrade on sync * workin * almost working * working1 * Update cmd/keycmd/transfer.go Co-authored-by: Meaghan FitzGerald Signed-off-by: felipemadero * fix some lint * address PR comments * missing file * nit --------- Signed-off-by: felipemadero Signed-off-by: sukantoraymond Co-authored-by: Meaghan FitzGerald Co-authored-by: sukantoraymond --- cmd/blockchaincmd/deploy.go | 105 ++++++++++- cmd/blockchaincmd/describe.go | 13 ++ cmd/blockchaincmd/prompt_genesis_input.go | 1 + cmd/blockchaincmd/upgradecmd/apply.go | 2 +- cmd/contractcmd/contract.go | 2 + cmd/contractcmd/init_poa_validator_manager.go | 132 +++++++++++++ cmd/nodecmd/create_devnet.go | 15 +- cmd/nodecmd/helpers.go | 19 +- cmd/nodecmd/sync.go | 2 +- cmd/nodecmd/upgrade.json | 16 ++ go.mod | 15 +- go.sum | 31 ++-- internal/mocks/binary_checker.go | 2 +- internal/mocks/downloader.go | 2 +- internal/mocks/installer.go | 2 +- internal/mocks/network.go | 2 +- internal/mocks/plugin_binary_downloader.go | 2 +- internal/mocks/process_checker.go | 2 +- internal/mocks/prompter.go | 173 ++++++++++++++++-- internal/mocks/publisher.go | 2 +- pkg/application/app.go | 4 +- pkg/constants/constants.go | 7 +- pkg/evm/evm.go | 75 +++++++- pkg/prompts/prompts.go | 8 +- pkg/prompts/validations.go | 7 + pkg/remoteconfig/avalanche.go | 53 +++--- .../templates/avalanche-node.tmpl | 4 + pkg/ssh/ssh.go | 15 ++ pkg/subnet/public.go | 107 ++++++++++- pkg/ux/progressbar.go | 47 +++++ pkg/ux/spinner.go | 2 + pkg/validatormanager/validatormanager.go | 22 +-- pkg/vm/precompiles.go | 3 +- scripts/regenerate_mocks.sh | 8 +- tests/e2e/testcases/upgrade/non-sov/suite.go | 2 +- tests/e2e/testcases/upgrade/sov/suite.go | 2 +- 36 files changed, 791 insertions(+), 115 deletions(-) create mode 100644 cmd/contractcmd/init_poa_validator_manager.go create mode 100644 cmd/nodecmd/upgrade.json create mode 100644 pkg/ux/progressbar.go diff --git a/cmd/blockchaincmd/deploy.go b/cmd/blockchaincmd/deploy.go index c0e05e322..fc38d9da5 100644 --- a/cmd/blockchaincmd/deploy.go +++ b/cmd/blockchaincmd/deploy.go @@ -9,9 +9,12 @@ import ( "os" "path/filepath" "strings" + "time" "github.com/ava-labs/avalanchego/vms/platformvm/warp/message" + "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/avalanche-cli/pkg/contract" "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanchego/utils/formatting/address" "github.com/ava-labs/avalanchego/vms/platformvm/fx" @@ -29,6 +32,7 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/subnet" "github.com/ava-labs/avalanche-cli/pkg/txutils" "github.com/ava-labs/avalanche-cli/pkg/ux" + "github.com/ava-labs/avalanche-cli/pkg/validatormanager" "github.com/ava-labs/avalanche-cli/pkg/vm" anrutils "github.com/ava-labs/avalanche-network-runner/utils" "github.com/ava-labs/avalanchego/ids" @@ -67,6 +71,7 @@ var ( icmSpec subnet.ICMSpec generateNodeID bool bootstrapValidatorsJSONFilePath string + privateKeyFlags contract.PrivateKeyFlags errMutuallyExlusiveControlKeys = errors.New("--control-keys and --same-control-key are mutually exclusive") ErrMutuallyExlusiveKeyLedger = errors.New("key source flags --key, --ledger/--ledger-addrs are mutually exclusive") @@ -94,6 +99,8 @@ so you can take your locally tested Subnet and deploy it on Fuji or Mainnet.`, Args: cobrautils.ExactArgs(1), } networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, deploySupportedNetworkOptions) + privateKeyFlags.SetFlagNames("blockchain-private-key", "blockchain-key", "blockchain-genesis-key") + privateKeyFlags.AddToCmd(cmd, "to fund validator manager initialization") cmd.Flags().StringVar(&userProvidedAvagoVersion, "avalanchego-version", "latest", "use this version of avalanchego (ex: v1.17.12)") cmd.Flags().StringVarP(&keyName, "key", "k", "", "select the key to use [fuji/devnet deploy only]") cmd.Flags().BoolVarP(&sameControlKey, "same-control-key", "s", false, "use the fee-paying key as control key") @@ -559,6 +566,7 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { if err != nil { return err } + deployer.CleanCacheWallet() // get the control keys in the same order as the tx _, controlKeys, threshold, err = txutils.GetOwners(network, subnetID) if err != nil { @@ -610,21 +618,25 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { } if sidecar.Sovereign { - avaGoBootstrapValidators, err := convertToAvalancheGoSubnetValidator(bootstrapValidators) + avaGoBootstrapValidators, err := ConvertToAvalancheGoSubnetValidator(bootstrapValidators) if err != nil { return err } + deployer.CleanCacheWallet() + managerAddress := common.HexToAddress(validatormanager.ValidatorContractAddress) isFullySigned, ConvertL1TxID, tx, remainingSubnetAuthKeys, err := deployer.ConvertL1( controlKeys, subnetAuthKeys, subnetID, blockchainID, + managerAddress, avaGoBootstrapValidators, ) if err != nil { ux.Logger.PrintToUser(logging.Red.Wrap( fmt.Sprintf("error converting blockchain: %s. fix the issue and try again with a new convert cmd", err), )) + return err } savePartialTx = !isFullySigned && err == nil @@ -643,6 +655,93 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { return err } } + + bar, err := ux.TimedProgressBar( + 30*time.Second, + "Waiting for Blockchain to be converted into Subnet Only Validator (SOV) Blockchain ...", + 2, + ) + if err != nil { + return err + } + + // Issue random transaction >30s after ConverSubnetTx to evict its block from the block map + _, _, err = deployer.PChainTransfer(kc.Addresses().List()[0], 1) + if err != nil { + return err + } + if err := ux.ExtraStepExecuted(bar); err != nil { + return err + } + // Issue random transaction to advance the p-chain height now that the + // ConvertSubnetTx block isn't in the block map + _, _, err = deployer.PChainTransfer(kc.Addresses().List()[0], 1) + if err != nil { + return err + } + if err := ux.ExtraStepExecuted(bar); err != nil { + return err + } + fmt.Println() + + if err := app.UpdateSidecarNetworks(&sidecar, network, subnetID, blockchainID, "", "", bootstrapValidators); err != nil { + return err + } + + if false { + chainSpec := contract.ChainSpec{ + BlockchainName: blockchainName, + } + genesisAddress, genesisPrivateKey, err := contract.GetEVMSubnetPrefundedKey( + app, + network, + chainSpec, + ) + if err != nil { + return err + } + privateKey, err := privateKeyFlags.GetPrivateKey(app, genesisPrivateKey) + if err != nil { + return err + } + if privateKey == "" { + privateKey, err = prompts.PromptPrivateKey( + app.Prompt, + "Which key to you want to use to pay for initializing Validator Manager contract? (Uses Blockchain gas token)", + app.GetKeyDir(), + app.GetKey, + genesisAddress, + genesisPrivateKey, + ) + if err != nil { + return err + } + } + rpcURL, _, err := contract.GetBlockchainEndpoints( + app, + network, + chainSpec, + true, + false, + ) + if err != nil { + return err + } + if err := validatormanager.SetupPoA( + app, + network, + rpcURL, + contract.ChainSpec{ + BlockchainName: blockchainName, + }, + privateKey, + common.HexToAddress(sidecar.PoAValidatorManagerOwner), + avaGoBootstrapValidators, + ); err != nil { + return err + } + ux.Logger.GreenCheckmarkToUser("Subnet is successfully converted into Subnet Only Validator") + } } flags := make(map[string]string) @@ -651,7 +750,7 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { // update sidecar // TODO: need to do something for backwards compatibility? - return app.UpdateSidecarNetworks(&sidecar, network, subnetID, blockchainID, "", "", bootstrapValidators) + return nil } func getBLSInfo(publicKey, proofOfPossesion string) (signer.ProofOfPossession, error) { @@ -676,7 +775,7 @@ func getBLSInfo(publicKey, proofOfPossesion string) (signer.ProofOfPossession, e } // TODO: add deactivation owner? -func convertToAvalancheGoSubnetValidator(subnetValidators []models.SubnetValidator) ([]*txs.ConvertSubnetValidator, error) { +func ConvertToAvalancheGoSubnetValidator(subnetValidators []models.SubnetValidator) ([]*txs.ConvertSubnetValidator, error) { bootstrapValidators := []*txs.ConvertSubnetValidator{} for _, validator := range subnetValidators { nodeID, err := ids.NodeIDFromString(validator.NodeID) diff --git a/cmd/blockchaincmd/describe.go b/cmd/blockchaincmd/describe.go index e62ab66f1..7bbaed6cf 100644 --- a/cmd/blockchaincmd/describe.go +++ b/cmd/blockchaincmd/describe.go @@ -162,6 +162,19 @@ func PrintSubnetInfo(blockchainName string, onlyLocalnetInfo bool) error { t.AppendRow(table.Row{net, "BlockchainID (CB58)", data.BlockchainID.String()}) t.AppendRow(table.Row{net, "BlockchainID (HEX)", hexEncoding}) } + endpoint, _, err := contract.GetBlockchainEndpoints( + app, + network, + contract.ChainSpec{ + BlockchainName: sc.Name, + }, + false, + false, + ) + if err != nil { + return err + } + t.AppendRow(table.Row{net, "RPC Endpoint", endpoint}) } ux.Logger.PrintToUser(t.Render()) diff --git a/cmd/blockchaincmd/prompt_genesis_input.go b/cmd/blockchaincmd/prompt_genesis_input.go index 3c92a4172..842a2cc45 100644 --- a/cmd/blockchaincmd/prompt_genesis_input.go +++ b/cmd/blockchaincmd/prompt_genesis_input.go @@ -122,6 +122,7 @@ func promptBootstrapValidators(network models.Network) ([]models.SubnetValidator var subnetValidators []models.SubnetValidator numBootstrapValidators, err := app.Prompt.CaptureInt( "How many bootstrap validators do you want to set up?", + prompts.ValidatePositiveInt, ) if err != nil { return nil, err diff --git a/cmd/blockchaincmd/upgradecmd/apply.go b/cmd/blockchaincmd/upgradecmd/apply.go index 744c348a6..2df242a29 100644 --- a/cmd/blockchaincmd/upgradecmd/apply.go +++ b/cmd/blockchaincmd/upgradecmd/apply.go @@ -305,7 +305,7 @@ func applyPublicNetworkUpgrade(blockchainName, networkKey string, sc *models.Sid ux.Logger.PrintToUser("Trying to install the upgrade files at the provided %s path", avalanchegoChainConfigDir) chainDir := filepath.Join(avalanchegoChainConfigDir, sc.Networks[networkKey].BlockchainID.String()) - destPath := filepath.Join(chainDir, constants.UpgradeBytesFileName) + destPath := filepath.Join(chainDir, constants.UpgradeFileName) if err = os.Mkdir(chainDir, constants.DefaultPerms755); err != nil && !os.IsExist(err) { return fmt.Errorf("failed to create blockchain directory: %w", err) } diff --git a/cmd/contractcmd/contract.go b/cmd/contractcmd/contract.go index 84df73504..b4e606f92 100644 --- a/cmd/contractcmd/contract.go +++ b/cmd/contractcmd/contract.go @@ -22,5 +22,7 @@ and interacting with smart contracts.`, app = injectedApp // contract deploy cmd.AddCommand(newDeployCmd()) + // contract initpoamanager + cmd.AddCommand(newInitPOAManagerCmd()) return cmd } diff --git a/cmd/contractcmd/init_poa_validator_manager.go b/cmd/contractcmd/init_poa_validator_manager.go new file mode 100644 index 000000000..940f56290 --- /dev/null +++ b/cmd/contractcmd/init_poa_validator_manager.go @@ -0,0 +1,132 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. +package contractcmd + +import ( + "fmt" + + "github.com/ava-labs/avalanche-cli/cmd/blockchaincmd" + "github.com/ava-labs/avalanche-cli/pkg/cobrautils" + "github.com/ava-labs/avalanche-cli/pkg/contract" + "github.com/ava-labs/avalanche-cli/pkg/networkoptions" + "github.com/ava-labs/avalanche-cli/pkg/prompts" + "github.com/ava-labs/avalanche-cli/pkg/ux" + "github.com/ava-labs/avalanche-cli/pkg/validatormanager" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ethereum/go-ethereum/common" + + "github.com/spf13/cobra" +) + +type InitPOAManagerFlags struct { + Network networkoptions.NetworkFlags + PrivateKeyFlags contract.PrivateKeyFlags + rpcEndpoint string +} + +var ( + initPOAManagerSupportedNetworkOptions = []networkoptions.NetworkOption{ + networkoptions.Local, + networkoptions.Devnet, + networkoptions.Fuji, + } + initPOAManagerFlags InitPOAManagerFlags +) + +// avalanche contract initpoamanager +func newInitPOAManagerCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "initPoaManager", + Short: "Initializes a Proof of Authority Validator Manager on a given Network and Blockchain", + Long: "Initializes Proof of Authority Validator Manager contract on a Blockchain and sets up initial validator set on the Blockchain. For more info on Validator Manager, please head to https://github.com/ava-labs/teleporter/tree/staking-contract/contracts/validator-manager", + RunE: initPOAManager, + Args: cobrautils.ExactArgs(1), + } + networkoptions.AddNetworkFlagsToCmd(cmd, &initPOAManagerFlags.Network, true, initPOAManagerSupportedNetworkOptions) + initPOAManagerFlags.PrivateKeyFlags.AddToCmd(cmd, "as contract deployer") + cmd.Flags().StringVar(&initPOAManagerFlags.rpcEndpoint, "rpc", "", "deploy the contract into the given rpc endpoint") + return cmd +} + +func initPOAManager(_ *cobra.Command, args []string) error { + blockchainName := args[0] + chainSpec := contract.ChainSpec{ + BlockchainName: blockchainName, + } + network, err := networkoptions.GetNetworkFromCmdLineFlags( + app, + "", + initPOAManagerFlags.Network, + true, + false, + initPOAManagerSupportedNetworkOptions, + "", + ) + if err != nil { + return err + } + if initPOAManagerFlags.rpcEndpoint == "" { + initPOAManagerFlags.rpcEndpoint, _, err = contract.GetBlockchainEndpoints( + app, + network, + chainSpec, + true, + false, + ) + if err != nil { + return err + } + } + ux.Logger.PrintToUser(logging.Yellow.Wrap("RPC Endpoint: %s"), initPOAManagerFlags.rpcEndpoint) + genesisAddress, genesisPrivateKey, err := contract.GetEVMSubnetPrefundedKey( + app, + network, + chainSpec, + ) + if err != nil { + return err + } + privateKey, err := initPOAManagerFlags.PrivateKeyFlags.GetPrivateKey(app, genesisPrivateKey) + if err != nil { + return err + } + if privateKey == "" { + privateKey, err = prompts.PromptPrivateKey( + app.Prompt, + "Which key to you want to use to pay for initializing Proof of Authority Validator Manager contract? (Uses Blockchain gas token)", + app.GetKeyDir(), + app.GetKey, + genesisAddress, + genesisPrivateKey, + ) + if err != nil { + return err + } + } + sc, err := app.LoadSidecar(chainSpec.BlockchainName) + if err != nil { + return fmt.Errorf("failed to load sidecar: %w", err) + } + if sc.Networks[network.Name()].BlockchainID == ids.Empty { + return fmt.Errorf("blockchain has not been deployed to %s", network.Name()) + } + bootstrapValidators := sc.Networks[network.Name()].BootstrapValidators + avaGoBootstrapValidators, err := blockchaincmd.ConvertToAvalancheGoSubnetValidator(bootstrapValidators) + if err != nil { + return err + } + if err := validatormanager.SetupPoA( + app, + network, + initPOAManagerFlags.rpcEndpoint, + chainSpec, + privateKey, + common.HexToAddress(sc.PoAValidatorManagerOwner), + avaGoBootstrapValidators, + ); err != nil { + return err + } + ux.Logger.GreenCheckmarkToUser("Proof of Authority Validator Manager contract successfully initialized on blockchain %s", blockchainName) + return nil +} diff --git a/cmd/nodecmd/create_devnet.go b/cmd/nodecmd/create_devnet.go index 889d0eb40..397556b3f 100644 --- a/cmd/nodecmd/create_devnet.go +++ b/cmd/nodecmd/create_devnet.go @@ -3,6 +3,7 @@ package nodecmd import ( + _ "embed" "encoding/json" "fmt" "os" @@ -41,6 +42,9 @@ const ( allocationCommonEthAddress = "0xb3d82b1367d362de99ab59a658165aff520cbd4d" ) +//go:embed upgrade.json +var upgradeBytes []byte + func generateCustomCchainGenesis() ([]byte, error) { cChainGenesisMap := map[string]interface{}{} cChainGenesisMap["config"] = coreth_params.GetChainConfig(avago_upgrade.GetConfig(avago_constants.LocalID), coreth_params.AvalancheLocalChainID) @@ -222,15 +226,20 @@ func setupDevnet(clusterName string, hosts []*models.Host, apiNodeIPMap map[stri confMap[config.NetworkNameKey] = fmt.Sprintf("network-%d", network.ID) confMap[config.BootstrapIDsKey] = strings.Join(bootstrapIDs, ",") confMap[config.BootstrapIPsKey] = strings.Join(bootstrapIPs, ",") - confMap[config.GenesisFileKey] = filepath.Join(constants.DockerNodeConfigPath, "genesis.json") + confMap[config.GenesisFileKey] = filepath.Join(constants.DockerNodeConfigPath, constants.GenesisFileName) + confMap[config.UpgradeFileKey] = filepath.Join(constants.DockerNodeConfigPath, constants.UpgradeFileName) + confMap[config.ProposerVMUseCurrentHeightKey] = constants.DevnetFlagsProposerVMUseCurrentHeight confBytes, err := json.MarshalIndent(confMap, "", " ") if err != nil { return err } - if err := os.WriteFile(filepath.Join(app.GetNodeInstanceDirPath(host.GetCloudID()), "genesis.json"), genesisBytes, constants.WriteReadReadPerms); err != nil { + if err := os.WriteFile(filepath.Join(app.GetNodeInstanceDirPath(host.GetCloudID()), constants.GenesisFileName), genesisBytes, constants.WriteReadReadPerms); err != nil { + return err + } + if err := os.WriteFile(filepath.Join(app.GetNodeInstanceDirPath(host.GetCloudID()), constants.UpgradeFileName), upgradeBytes, constants.WriteReadReadPerms); err != nil { return err } - if err := os.WriteFile(filepath.Join(app.GetNodeInstanceDirPath(host.GetCloudID()), "node.json"), confBytes, constants.WriteReadReadPerms); err != nil { + if err := os.WriteFile(filepath.Join(app.GetNodeInstanceDirPath(host.GetCloudID()), constants.NodeFileName), confBytes, constants.WriteReadReadPerms); err != nil { return err } if slices.Contains(hostsWithoutAPIIDs, host.NodeID) { diff --git a/cmd/nodecmd/helpers.go b/cmd/nodecmd/helpers.go index dc3c683f4..bf004988f 100644 --- a/cmd/nodecmd/helpers.go +++ b/cmd/nodecmd/helpers.go @@ -240,8 +240,10 @@ func getWSEndpoint(endpoint string, blockchainID string) string { return models.NewDevnetNetwork(endpoint, 0).BlockchainWSEndpoint(blockchainID) } -func getPublicEndpoints(clusterName string) ([]string, error) { - endpoints := []string{} +func getPublicEndpoints( + clusterName string, + trackers []*models.Host, +) ([]string, error) { clusterConfig, err := app.GetClusterConfig(clusterName) if err != nil { return nil, err @@ -250,12 +252,11 @@ func getPublicEndpoints(clusterName string) ([]string, error) { if clusterConfig.Network.Kind == models.Devnet { publicNodes = clusterConfig.Nodes } - for _, cloudID := range publicNodes { - nodeConfig, err := app.LoadClusterNodeConfig(cloudID) - if err != nil { - return nil, err - } - endpoints = append(endpoints, getAvalancheGoEndpoint(nodeConfig.ElasticIP)) - } + publicTrackers := utils.Filter(trackers, func(tracker *models.Host) bool { + return utils.Belongs(publicNodes, tracker.GetCloudID()) + }) + endpoints := utils.Map(publicTrackers, func(tracker *models.Host) string { + return getAvalancheGoEndpoint(tracker.IP) + }) return endpoints, nil } diff --git a/cmd/nodecmd/sync.go b/cmd/nodecmd/sync.go index 06a699d02..1eeea041e 100644 --- a/cmd/nodecmd/sync.go +++ b/cmd/nodecmd/sync.go @@ -181,7 +181,7 @@ func trackSubnet( networkInfo := sc.Networks[clusterConfig.Network.Name()] rpcEndpoints := set.Of(networkInfo.RPCEndpoints...) wsEndpoints := set.Of(networkInfo.WSEndpoints...) - publicEndpoints, err := getPublicEndpoints(clusterName) + publicEndpoints, err := getPublicEndpoints(clusterName, hosts) if err != nil { return err } diff --git a/cmd/nodecmd/upgrade.json b/cmd/nodecmd/upgrade.json new file mode 100644 index 000000000..ca3a7f13a --- /dev/null +++ b/cmd/nodecmd/upgrade.json @@ -0,0 +1,16 @@ +{ + "apricotPhase1Time": "2020-12-05T05:00:00Z", + "apricotPhase2Time": "2020-12-05T05:00:00Z", + "apricotPhase3Time": "2020-12-05T05:00:00Z", + "apricotPhase4Time": "2020-12-05T05:00:00Z", + "apricotPhase4MinPChainHeight": 0, + "apricotPhase5Time": "2020-12-05T05:00:00Z", + "apricotPhasePre6Time": "2020-12-05T05:00:00Z", + "apricotPhase6Time": "2020-12-05T05:00:00Z", + "apricotPhasePost6Time": "2020-12-05T05:00:00Z", + "banffTime": "2020-12-05T05:00:00Z", + "cortinaTime": "2020-12-05T05:00:00Z", + "cortinaXChainStopVertexID": "11111111111111111111111111111111LpoYY", + "durangoTime": "2020-12-05T05:00:00Z", + "etnaTime": "2020-12-05T05:00:00Z" +} diff --git a/go.mod b/go.mod index 81bb963a6..3776779d4 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,8 @@ go 1.22.8 require ( github.com/ava-labs/apm v1.0.0 - github.com/ava-labs/avalanche-network-runner v1.8.4-0.20240930181211-bfc2f5f85973 - github.com/ava-labs/avalanchego v1.12.0-initial-poc.2 + github.com/ava-labs/avalanche-network-runner v1.8.4-0.20241005224128-cc3c07bb1344 + github.com/ava-labs/avalanchego v1.12.0-initial-poc.3 github.com/ava-labs/awm-relayer v1.4.1-0.20241003162124-807fd305670f github.com/ava-labs/coreth v0.13.8 github.com/ava-labs/subnet-evm v0.6.10 @@ -18,6 +18,7 @@ require ( github.com/fatih/color v1.17.0 github.com/go-git/go-git/v5 v5.12.0 github.com/jedib0t/go-pretty/v6 v6.5.9 + github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 github.com/liyue201/erc20-go v0.0.0-20210521034206-b2824246def0 github.com/manifoldco/promptui v0.9.0 @@ -31,6 +32,7 @@ require ( github.com/pingcap/errors v0.11.4 github.com/posthog/posthog-go v1.2.24 github.com/prometheus/client_golang v1.20.4 + github.com/schollz/progressbar/v3 v3.16.1 github.com/shirou/gopsutil v3.21.11+incompatible github.com/spf13/afero v1.11.0 github.com/spf13/cobra v1.8.1 @@ -161,7 +163,8 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect @@ -178,7 +181,7 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/rivo/uniseg v0.2.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rs/cors v1.7.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect @@ -216,8 +219,8 @@ require ( go.opentelemetry.io/otel/trace v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/term v0.23.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/term v0.25.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.24.0 // indirect gonum.org/v1/gonum v0.11.0 // indirect diff --git a/go.sum b/go.sum index 388191e11..f7f98a76c 100644 --- a/go.sum +++ b/go.sum @@ -83,10 +83,10 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/ava-labs/apm v1.0.0 h1:6FwozH67hEkbWVsOXNZGexBy5KLpNeYucN9zcFUHv+Q= github.com/ava-labs/apm v1.0.0/go.mod h1:TJL7pTlZNvQatsQPsLUtDHApEwVZ/qS7iSNtRFU83mc= -github.com/ava-labs/avalanche-network-runner v1.8.4-0.20240930181211-bfc2f5f85973 h1:rsAfxjQLCs9dyDGqUZK29fGDrW4uzLzYjQLUVMEkvdQ= -github.com/ava-labs/avalanche-network-runner v1.8.4-0.20240930181211-bfc2f5f85973/go.mod h1:T6AYu2HBw4N6oAIRJWATSLx3/uWLVVADTbfSCIcSlEY= -github.com/ava-labs/avalanchego v1.12.0-initial-poc.2 h1:Xsb9XUXW1wjtP2yULhpknW9Ghobm2U3PW3z1MqP0SkY= -github.com/ava-labs/avalanchego v1.12.0-initial-poc.2/go.mod h1:qSHmog3wMVjo/ruIAQo0ppXAilyni07NIu5K88RyhWE= +github.com/ava-labs/avalanche-network-runner v1.8.4-0.20241005224128-cc3c07bb1344 h1:wD/rBr+QKztcKtRtBNqPjzMhwcxnVcuJ3GT62DdgS2Q= +github.com/ava-labs/avalanche-network-runner v1.8.4-0.20241005224128-cc3c07bb1344/go.mod h1:l4QzFnujbyyyeq6oBQ4F6sw9TrTQCjD2V4vUd7ZBCCo= +github.com/ava-labs/avalanchego v1.12.0-initial-poc.3 h1:JfVooBCdMzpeGUT9/phJNl2GHflkGehlMJokXeWKa2A= +github.com/ava-labs/avalanchego v1.12.0-initial-poc.3/go.mod h1:qSHmog3wMVjo/ruIAQo0ppXAilyni07NIu5K88RyhWE= github.com/ava-labs/awm-relayer v1.4.1-0.20241003162124-807fd305670f h1:YUQF1wQJeEcTMC5W/OrwgSFTFMS4zeCM8O02rLeEDow= github.com/ava-labs/awm-relayer v1.4.1-0.20241003162124-807fd305670f/go.mod h1:K01Md6zPkOFRWeQyxmZ/t9HJfoNgUGqa1L8rOp35GXw= github.com/ava-labs/coreth v0.13.8 h1:f14X3KgwHl9LwzfxlN6S4bbn5VA2rhEsNnHaRLSTo/8= @@ -185,6 +185,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chelnak/ysmrr v0.4.0 h1:WMvLGPlBK0kb6wHf5z9FfNvpM6sB9765jy2ajYc1Sfs= github.com/chelnak/ysmrr v0.4.0/go.mod h1:8vCna4PJsPCb6eevtoG7Tljzfx3twpsO203Qj2gafLM= +github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM= +github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= @@ -555,6 +557,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg= +github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= @@ -626,8 +630,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= @@ -636,6 +640,8 @@ github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i github.com/melbahja/goph v1.4.0 h1:z0PgDbBFe66lRYl3v5dGb9aFgPy0kotuQ37QOwSQFqs= github.com/melbahja/goph v1.4.0/go.mod h1:uG+VfK2Dlhk+O32zFrRlc3kYKTlV6+BtvPWd/kK7U68= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= @@ -752,8 +758,9 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= @@ -775,6 +782,8 @@ github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWR github.com/sanity-io/litter v1.5.1 h1:dwnrSypP6q56o3lFxTU+t2fwQ9A+U5qrXVO4Qg9KwVU= github.com/sanity-io/litter v1.5.1/go.mod h1:5Z71SvaYy5kcGtyglXOC9rrUi3c1E8CamFWjQsazTh0= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= +github.com/schollz/progressbar/v3 v3.16.1 h1:RnF1neWZFzLCoGx8yp1yF7SDl4AzNDI5y4I0aUJRrZQ= +github.com/schollz/progressbar/v3 v3.16.1/go.mod h1:I2ILR76gz5VXqYMIY/LdLecvMHDPVcQm3W/MSKi1TME= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -1110,16 +1119,16 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= diff --git a/internal/mocks/binary_checker.go b/internal/mocks/binary_checker.go index 885860e52..ec21488b8 100644 --- a/internal/mocks/binary_checker.go +++ b/internal/mocks/binary_checker.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/internal/mocks/downloader.go b/internal/mocks/downloader.go index c119d797a..1a1f45c9a 100644 --- a/internal/mocks/downloader.go +++ b/internal/mocks/downloader.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/internal/mocks/installer.go b/internal/mocks/installer.go index 323ff8645..5fa59ad64 100644 --- a/internal/mocks/installer.go +++ b/internal/mocks/installer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/internal/mocks/network.go b/internal/mocks/network.go index 0a09ba3ed..56ce44811 100644 --- a/internal/mocks/network.go +++ b/internal/mocks/network.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/internal/mocks/plugin_binary_downloader.go b/internal/mocks/plugin_binary_downloader.go index 465ebf69e..1972dbd49 100644 --- a/internal/mocks/plugin_binary_downloader.go +++ b/internal/mocks/plugin_binary_downloader.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/internal/mocks/process_checker.go b/internal/mocks/process_checker.go index 39602919b..2398cd337 100644 --- a/internal/mocks/process_checker.go +++ b/internal/mocks/process_checker.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/internal/mocks/prompter.go b/internal/mocks/prompter.go index d9fa0f805..67991970f 100644 --- a/internal/mocks/prompter.go +++ b/internal/mocks/prompter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.26.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -28,6 +28,10 @@ type Prompter struct { func (_m *Prompter) CaptureAddress(promptStr string) (common.Address, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureAddress") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(string) (common.Address, error)); ok { @@ -54,6 +58,10 @@ func (_m *Prompter) CaptureAddress(promptStr string) (common.Address, error) { func (_m *Prompter) CaptureAddresses(promptStr string) ([]common.Address, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureAddresses") + } + var r0 []common.Address var r1 error if rf, ok := ret.Get(0).(func(string) ([]common.Address, error)); ok { @@ -80,6 +88,10 @@ func (_m *Prompter) CaptureAddresses(promptStr string) ([]common.Address, error) func (_m *Prompter) CaptureDate(promptStr string) (time.Time, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureDate") + } + var r0 time.Time var r1 error if rf, ok := ret.Get(0).(func(string) (time.Time, error)); ok { @@ -104,6 +116,10 @@ func (_m *Prompter) CaptureDate(promptStr string) (time.Time, error) { func (_m *Prompter) CaptureEmail(promptStr string) (string, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureEmail") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(string) (string, error)); ok { @@ -128,6 +144,10 @@ func (_m *Prompter) CaptureEmail(promptStr string) (string, error) { func (_m *Prompter) CaptureExistingFilepath(promptStr string) (string, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureExistingFilepath") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(string) (string, error)); ok { @@ -152,6 +172,10 @@ func (_m *Prompter) CaptureExistingFilepath(promptStr string) (string, error) { func (_m *Prompter) CaptureFloat(promptStr string, validator func(float64) error) (float64, error) { ret := _m.Called(promptStr, validator) + if len(ret) == 0 { + panic("no return value specified for CaptureFloat") + } + var r0 float64 var r1 error if rf, ok := ret.Get(0).(func(string, func(float64) error) (float64, error)); ok { @@ -176,6 +200,10 @@ func (_m *Prompter) CaptureFloat(promptStr string, validator func(float64) error func (_m *Prompter) CaptureFujiDuration(promptStr string) (time.Duration, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureFujiDuration") + } + var r0 time.Duration var r1 error if rf, ok := ret.Get(0).(func(string) (time.Duration, error)); ok { @@ -200,6 +228,10 @@ func (_m *Prompter) CaptureFujiDuration(promptStr string) (time.Duration, error) func (_m *Prompter) CaptureFutureDate(promptStr string, minDate time.Time) (time.Time, error) { ret := _m.Called(promptStr, minDate) + if len(ret) == 0 { + panic("no return value specified for CaptureFutureDate") + } + var r0 time.Time var r1 error if rf, ok := ret.Get(0).(func(string, time.Time) (time.Time, error)); ok { @@ -224,6 +256,10 @@ func (_m *Prompter) CaptureFutureDate(promptStr string, minDate time.Time) (time func (_m *Prompter) CaptureGitURL(promptStr string) (*url.URL, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureGitURL") + } + var r0 *url.URL var r1 error if rf, ok := ret.Get(0).(func(string) (*url.URL, error)); ok { @@ -250,6 +286,10 @@ func (_m *Prompter) CaptureGitURL(promptStr string) (*url.URL, error) { func (_m *Prompter) CaptureID(promptStr string) (ids.ID, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureID") + } + var r0 ids.ID var r1 error if rf, ok := ret.Get(0).(func(string) (ids.ID, error)); ok { @@ -276,6 +316,10 @@ func (_m *Prompter) CaptureID(promptStr string) (ids.ID, error) { func (_m *Prompter) CaptureIndex(promptStr string, options []interface{}) (int, error) { ret := _m.Called(promptStr, options) + if len(ret) == 0 { + panic("no return value specified for CaptureIndex") + } + var r0 int var r1 error if rf, ok := ret.Get(0).(func(string, []interface{}) (int, error)); ok { @@ -296,23 +340,27 @@ func (_m *Prompter) CaptureIndex(promptStr string, options []interface{}) (int, return r0, r1 } -// CaptureInt provides a mock function with given fields: promptStr -func (_m *Prompter) CaptureInt(promptStr string) (int, error) { - ret := _m.Called(promptStr) +// CaptureInt provides a mock function with given fields: promptStr, validator +func (_m *Prompter) CaptureInt(promptStr string, validator func(int) error) (int, error) { + ret := _m.Called(promptStr, validator) + + if len(ret) == 0 { + panic("no return value specified for CaptureInt") + } var r0 int var r1 error - if rf, ok := ret.Get(0).(func(string) (int, error)); ok { - return rf(promptStr) + if rf, ok := ret.Get(0).(func(string, func(int) error) (int, error)); ok { + return rf(promptStr, validator) } - if rf, ok := ret.Get(0).(func(string) int); ok { - r0 = rf(promptStr) + if rf, ok := ret.Get(0).(func(string, func(int) error) int); ok { + r0 = rf(promptStr, validator) } else { r0 = ret.Get(0).(int) } - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(promptStr) + if rf, ok := ret.Get(1).(func(string, func(int) error) error); ok { + r1 = rf(promptStr, validator) } else { r1 = ret.Error(1) } @@ -324,6 +372,10 @@ func (_m *Prompter) CaptureInt(promptStr string) (int, error) { func (_m *Prompter) CaptureList(promptStr string, options []string) (string, error) { ret := _m.Called(promptStr, options) + if len(ret) == 0 { + panic("no return value specified for CaptureList") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(string, []string) (string, error)); ok { @@ -348,6 +400,10 @@ func (_m *Prompter) CaptureList(promptStr string, options []string) (string, err func (_m *Prompter) CaptureListWithSize(promptStr string, options []string, size int) (string, error) { ret := _m.Called(promptStr, options, size) + if len(ret) == 0 { + panic("no return value specified for CaptureListWithSize") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(string, []string, int) (string, error)); ok { @@ -372,6 +428,10 @@ func (_m *Prompter) CaptureListWithSize(promptStr string, options []string, size func (_m *Prompter) CaptureMainnetDuration(promptStr string) (time.Duration, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureMainnetDuration") + } + var r0 time.Duration var r1 error if rf, ok := ret.Get(0).(func(string) (time.Duration, error)); ok { @@ -396,6 +456,10 @@ func (_m *Prompter) CaptureMainnetDuration(promptStr string) (time.Duration, err func (_m *Prompter) CaptureNewFilepath(promptStr string) (string, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureNewFilepath") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(string) (string, error)); ok { @@ -420,6 +484,10 @@ func (_m *Prompter) CaptureNewFilepath(promptStr string) (string, error) { func (_m *Prompter) CaptureNoYes(promptStr string) (bool, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureNoYes") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(string) (bool, error)); ok { @@ -444,6 +512,10 @@ func (_m *Prompter) CaptureNoYes(promptStr string) (bool, error) { func (_m *Prompter) CaptureNodeID(promptStr string) (ids.NodeID, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureNodeID") + } + var r0 ids.NodeID var r1 error if rf, ok := ret.Get(0).(func(string) (ids.NodeID, error)); ok { @@ -470,6 +542,10 @@ func (_m *Prompter) CaptureNodeID(promptStr string) (ids.NodeID, error) { func (_m *Prompter) CapturePChainAddress(promptStr string, network models.Network) (string, error) { ret := _m.Called(promptStr, network) + if len(ret) == 0 { + panic("no return value specified for CapturePChainAddress") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(string, models.Network) (string, error)); ok { @@ -494,6 +570,10 @@ func (_m *Prompter) CapturePChainAddress(promptStr string, network models.Networ func (_m *Prompter) CapturePositiveBigInt(promptStr string) (*big.Int, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CapturePositiveBigInt") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(string) (*big.Int, error)); ok { @@ -520,6 +600,10 @@ func (_m *Prompter) CapturePositiveBigInt(promptStr string) (*big.Int, error) { func (_m *Prompter) CapturePositiveInt(promptStr string, comparators []prompts.Comparator) (int, error) { ret := _m.Called(promptStr, comparators) + if len(ret) == 0 { + panic("no return value specified for CapturePositiveInt") + } + var r0 int var r1 error if rf, ok := ret.Get(0).(func(string, []prompts.Comparator) (int, error)); ok { @@ -544,6 +628,10 @@ func (_m *Prompter) CapturePositiveInt(promptStr string, comparators []prompts.C func (_m *Prompter) CaptureRepoBranch(promptStr string, repo string) (string, error) { ret := _m.Called(promptStr, repo) + if len(ret) == 0 { + panic("no return value specified for CaptureRepoBranch") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(string, string) (string, error)); ok { @@ -568,6 +656,10 @@ func (_m *Prompter) CaptureRepoBranch(promptStr string, repo string) (string, er func (_m *Prompter) CaptureRepoFile(promptStr string, repo string, branch string) (string, error) { ret := _m.Called(promptStr, repo, branch) + if len(ret) == 0 { + panic("no return value specified for CaptureRepoFile") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(string, string, string) (string, error)); ok { @@ -592,6 +684,10 @@ func (_m *Prompter) CaptureRepoFile(promptStr string, repo string, branch string func (_m *Prompter) CaptureString(promptStr string) (string, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureString") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(string) (string, error)); ok { @@ -616,6 +712,10 @@ func (_m *Prompter) CaptureString(promptStr string) (string, error) { func (_m *Prompter) CaptureStringAllowEmpty(promptStr string) (string, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureStringAllowEmpty") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(string) (string, error)); ok { @@ -640,6 +740,10 @@ func (_m *Prompter) CaptureStringAllowEmpty(promptStr string) (string, error) { func (_m *Prompter) CaptureURL(promptStr string, validateConnection bool) (string, error) { ret := _m.Called(promptStr, validateConnection) + if len(ret) == 0 { + panic("no return value specified for CaptureURL") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(string, bool) (string, error)); ok { @@ -664,6 +768,10 @@ func (_m *Prompter) CaptureURL(promptStr string, validateConnection bool) (strin func (_m *Prompter) CaptureUint32(promptStr string) (uint32, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureUint32") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(string) (uint32, error)); ok { @@ -688,6 +796,10 @@ func (_m *Prompter) CaptureUint32(promptStr string) (uint32, error) { func (_m *Prompter) CaptureUint64(promptStr string) (uint64, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureUint64") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(string) (uint64, error)); ok { @@ -712,6 +824,10 @@ func (_m *Prompter) CaptureUint64(promptStr string) (uint64, error) { func (_m *Prompter) CaptureUint64Compare(promptStr string, comparators []prompts.Comparator) (uint64, error) { ret := _m.Called(promptStr, comparators) + if len(ret) == 0 { + panic("no return value specified for CaptureUint64Compare") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(string, []prompts.Comparator) (uint64, error)); ok { @@ -736,6 +852,10 @@ func (_m *Prompter) CaptureUint64Compare(promptStr string, comparators []prompts func (_m *Prompter) CaptureValidatedString(promptStr string, validator func(string) error) (string, error) { ret := _m.Called(promptStr, validator) + if len(ret) == 0 { + panic("no return value specified for CaptureValidatedString") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(string, func(string) error) (string, error)); ok { @@ -760,6 +880,10 @@ func (_m *Prompter) CaptureValidatedString(promptStr string, validator func(stri func (_m *Prompter) CaptureValidatorBalance(promptStr string) (uint64, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureValidatorBalance") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(string) (uint64, error)); ok { @@ -784,6 +908,10 @@ func (_m *Prompter) CaptureValidatorBalance(promptStr string) (uint64, error) { func (_m *Prompter) CaptureVersion(promptStr string) (string, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureVersion") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(string) (string, error)); ok { @@ -808,6 +936,10 @@ func (_m *Prompter) CaptureVersion(promptStr string) (string, error) { func (_m *Prompter) CaptureWeight(promptStr string) (uint64, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureWeight") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(string) (uint64, error)); ok { @@ -832,6 +964,10 @@ func (_m *Prompter) CaptureWeight(promptStr string) (uint64, error) { func (_m *Prompter) CaptureXChainAddress(promptStr string, network models.Network) (string, error) { ret := _m.Called(promptStr, network) + if len(ret) == 0 { + panic("no return value specified for CaptureXChainAddress") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(string, models.Network) (string, error)); ok { @@ -856,6 +992,10 @@ func (_m *Prompter) CaptureXChainAddress(promptStr string, network models.Networ func (_m *Prompter) CaptureYesNo(promptStr string) (bool, error) { ret := _m.Called(promptStr) + if len(ret) == 0 { + panic("no return value specified for CaptureYesNo") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(string) (bool, error)); ok { @@ -880,6 +1020,10 @@ func (_m *Prompter) CaptureYesNo(promptStr string) (bool, error) { func (_m *Prompter) ChooseKeyOrLedger(goal string) (bool, error) { ret := _m.Called(goal) + if len(ret) == 0 { + panic("no return value specified for ChooseKeyOrLedger") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(string) (bool, error)); ok { @@ -900,13 +1044,12 @@ func (_m *Prompter) ChooseKeyOrLedger(goal string) (bool, error) { return r0, r1 } -type mockConstructorTestingTNewPrompter interface { +// NewPrompter creates a new instance of Prompter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewPrompter(t interface { mock.TestingT Cleanup(func()) -} - -// NewPrompter creates a new instance of Prompter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewPrompter(t mockConstructorTestingTNewPrompter) *Prompter { +}) *Prompter { mock := &Prompter{} mock.Mock.Test(t) diff --git a/internal/mocks/publisher.go b/internal/mocks/publisher.go index 743dbe573..45d6028a6 100644 --- a/internal/mocks/publisher.go +++ b/internal/mocks/publisher.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/pkg/application/app.go b/pkg/application/app.go index 474f5e247..c1668f8d9 100644 --- a/pkg/application/app.go +++ b/pkg/application/app.go @@ -160,7 +160,7 @@ func (app *Avalanche) GetSubnetEVMBinDir() string { } func (app *Avalanche) GetUpgradeBytesFilepath(blockchainName string) string { - return filepath.Join(app.GetSubnetDir(), blockchainName, constants.UpgradeBytesFileName) + return filepath.Join(app.GetSubnetDir(), blockchainName, constants.UpgradeFileName) } func (app *Avalanche) GetCustomVMPath(blockchainName string) string { @@ -286,7 +286,7 @@ func (app *Avalanche) GetKey(keyName string, network models.Network, createIfMis } func (app *Avalanche) GetUpgradeBytesFilePath(blockchainName string) string { - return filepath.Join(app.GetSubnetDir(), blockchainName, constants.UpgradeBytesFileName) + return filepath.Join(app.GetSubnetDir(), blockchainName, constants.UpgradeFileName) } func (app *Avalanche) GetDownloader() Downloader { diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 6e2d3b62a..72edee75c 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -26,6 +26,7 @@ const ( SuffixSeparator = "_" SidecarFileName = "sidecar.json" GenesisFileName = "genesis.json" + UpgradeFileName = "upgrade.json" AliasesFileName = "aliases.json" SidecarSuffix = SuffixSeparator + SidecarFileName GenesisSuffix = SuffixSeparator + GenesisFileName @@ -154,7 +155,8 @@ const ( TimeParseLayout = "2006-01-02 15:04:05" MinStakeWeight = 1 // Default balance when we prompt users for bootstrap validators - BootstrapValidatorBalance = 1 + // nAVAX + BootstrapValidatorBalance = 1000000000 // Default weight when we prompt users for bootstrap validators BootstrapValidatorWeight = 1000000 DefaultStakeWeight = 20 @@ -274,6 +276,8 @@ const ( DevnetLocalAWMRelayerMetricsPort = 9092 FujiLocalAWMRelayerMetricsPort = 9093 + DevnetFlagsProposerVMUseCurrentHeight = true + SubnetEVMBin = "subnet-evm" DefaultNodeRunURL = "http://127.0.0.1:9650" @@ -328,7 +332,6 @@ const ( AvalancheGoDockerImage = "avaplatform/avalanchego" AvalancheGoGitRepo = "https://github.com/ava-labs/avalanchego" - UpgradeBytesFileName = "upgrade.json" UpgradeBytesLockExtension = ".lock" NotAvailableLabel = "Not available" BackendCmd = "avalanche-cli-backend" diff --git a/pkg/evm/evm.go b/pkg/evm/evm.go index 300d34eed..eb3aea977 100644 --- a/pkg/evm/evm.go +++ b/pkg/evm/evm.go @@ -3,6 +3,7 @@ package evm import ( + "context" "crypto/ecdsa" "fmt" "math/big" @@ -15,10 +16,10 @@ import ( "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/ethclient" "github.com/ava-labs/subnet-evm/interfaces" + "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/contracts/warp" "github.com/ava-labs/subnet-evm/predicate" "github.com/ava-labs/subnet-evm/rpc" - subnetEvmTestUtils "github.com/ava-labs/subnet-evm/tests/utils" subnetEvmUtils "github.com/ava-labs/subnet-evm/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -518,7 +519,7 @@ func IssueTxsToActivateProposerVMFork( for i := 0; i < repeatsOnFailure; i++ { ctx, cancel := utils.GetAPILargeContext() defer cancel() - err = subnetEvmTestUtils.IssueTxsToActivateProposerVMFork(ctx, chainID, privKey, client) + err = issueTxsToActivateProposerVMFork(client, ctx, chainID, privKey) if err == nil { break } @@ -532,3 +533,73 @@ func IssueTxsToActivateProposerVMFork( } return err } + +// issueTxsToActivateProposerVMFork issues transactions at the current +// timestamp, which should be after the ProposerVM activation time (aka +// ApricotPhase4). This should generate a PostForkBlock because its parent block +// (genesis) has a timestamp (0) that is greater than or equal to the fork +// activation time of 0. Therefore, subsequent blocks should be built with +// BuildBlockWithContext. +func issueTxsToActivateProposerVMFork( + client ethclient.Client, + ctx context.Context, + chainID *big.Int, + fundedKey *ecdsa.PrivateKey, +) error { + const numTriggerTxs = 2 // Number of txs needed to activate the proposer VM fork + addr := crypto.PubkeyToAddress(fundedKey.PublicKey) + nonce, err := client.NonceAt(ctx, addr, nil) + if err != nil { + return err + } + + gasPrice := big.NewInt(params.MinGasPrice) + txSigner := types.LatestSignerForChainID(chainID) + for i := 0; i < numTriggerTxs; i++ { + prevBlockNumber, err := client.BlockNumber(ctx) + if err != nil { + return err + } + tx := types.NewTransaction( + nonce, addr, common.Big1, params.TxGas, gasPrice, nil) + triggerTx, err := types.SignTx(tx, txSigner, fundedKey) + if err != nil { + return err + } + if err := client.SendTransaction(ctx, triggerTx); err != nil { + return err + } + if err := WaitForNewBlock(client, ctx, prevBlockNumber, 0, 0); err != nil { + return err + } + nonce++ + } + return nil +} + +func WaitForNewBlock( + client ethclient.Client, + ctx context.Context, + prevBlockNumber uint64, + totalDuration time.Duration, + stepDuration time.Duration, +) error { + if stepDuration == 0 { + stepDuration = 1 * time.Second + } + if totalDuration == 0 { + totalDuration = 5 * time.Second + } + steps := totalDuration / stepDuration + for seconds := 0; seconds < int(steps); seconds++ { + blockNumber, err := client.BlockNumber(ctx) + if err != nil { + return err + } + if blockNumber > prevBlockNumber { + return nil + } + time.Sleep(stepDuration) + } + return fmt.Errorf("new block not produced in %f seconds", totalDuration.Seconds()) +} diff --git a/pkg/prompts/prompts.go b/pkg/prompts/prompts.go index 674798724..94af78ac8 100644 --- a/pkg/prompts/prompts.go +++ b/pkg/prompts/prompts.go @@ -108,7 +108,7 @@ type Prompter interface { CaptureWeight(promptStr string) (uint64, error) CaptureValidatorBalance(promptStr string) (uint64, error) CapturePositiveInt(promptStr string, comparators []Comparator) (int, error) - CaptureInt(promptStr string) (int, error) + CaptureInt(promptStr string, validator func(int) error) (int, error) CaptureUint32(promptStr string) (uint32, error) CaptureUint64(promptStr string) (uint64, error) CaptureFloat(promptStr string, validator func(float64) error) (float64, error) @@ -296,15 +296,15 @@ func (*realPrompter) CaptureWeight(promptStr string) (uint64, error) { return strconv.ParseUint(amountStr, 10, 64) } -func (*realPrompter) CaptureInt(promptStr string) (int, error) { +func (*realPrompter) CaptureInt(promptStr string, validator func(int) error) (int, error) { prompt := promptui.Prompt{ Label: promptStr, Validate: func(input string) error { - _, err := strconv.Atoi(input) + val, err := strconv.Atoi(input) if err != nil { return err } - return nil + return validator(val) }, } input, err := prompt.Run() diff --git a/pkg/prompts/validations.go b/pkg/prompts/validations.go index 38f2d2d35..1d6f4bad9 100644 --- a/pkg/prompts/validations.go +++ b/pkg/prompts/validations.go @@ -363,3 +363,10 @@ func ValidateHexa(input string) error { } return err } + +func ValidatePositiveInt(val int) error { + if val <= 0 { + return fmt.Errorf("value must be greater than cero") + } + return nil +} diff --git a/pkg/remoteconfig/avalanche.go b/pkg/remoteconfig/avalanche.go index 835e99851..181bc51f0 100644 --- a/pkg/remoteconfig/avalanche.go +++ b/pkg/remoteconfig/avalanche.go @@ -13,35 +13,38 @@ import ( ) type AvalancheConfigInputs struct { - HTTPHost string - APIAdminEnabled bool - IndexEnabled bool - NetworkID string - DBDir string - LogDir string - PublicIP string - StateSyncEnabled bool - PruningEnabled bool - Aliases []string - BlockChainID string - TrackSubnets string - BootstrapIDs string - BootstrapIPs string - GenesisPath string + HTTPHost string + APIAdminEnabled bool + IndexEnabled bool + NetworkID string + DBDir string + LogDir string + PublicIP string + StateSyncEnabled bool + PruningEnabled bool + Aliases []string + BlockChainID string + TrackSubnets string + BootstrapIDs string + BootstrapIPs string + GenesisPath string + UpgradePath string + ProposerVMUseCurrentHeight bool } func PrepareAvalancheConfig(publicIP string, networkID string, subnets []string) AvalancheConfigInputs { return AvalancheConfigInputs{ - HTTPHost: "127.0.0.1", - NetworkID: networkID, - DBDir: "/.avalanchego/db/", - LogDir: "/.avalanchego/logs/", - PublicIP: publicIP, - StateSyncEnabled: true, - PruningEnabled: false, - TrackSubnets: strings.Join(subnets, ","), - Aliases: nil, - BlockChainID: "", + HTTPHost: "127.0.0.1", + NetworkID: networkID, + DBDir: "/.avalanchego/db/", + LogDir: "/.avalanchego/logs/", + PublicIP: publicIP, + StateSyncEnabled: true, + PruningEnabled: false, + TrackSubnets: strings.Join(subnets, ","), + Aliases: nil, + BlockChainID: "", + ProposerVMUseCurrentHeight: constants.DevnetFlagsProposerVMUseCurrentHeight, } } diff --git a/pkg/remoteconfig/templates/avalanche-node.tmpl b/pkg/remoteconfig/templates/avalanche-node.tmpl index c5704fd1f..45d7849fd 100644 --- a/pkg/remoteconfig/templates/avalanche-node.tmpl +++ b/pkg/remoteconfig/templates/avalanche-node.tmpl @@ -2,6 +2,7 @@ "http-host": "{{.HTTPHost}}", "api-admin-enabled": {{.APIAdminEnabled}}, "index-enabled": {{.IndexEnabled}}, + "proposervm-use-current-height-bool": {{.ProposerVMUseCurrentHeight}}, "network-id": "{{if .NetworkID}}{{.NetworkID}}{{else}}fuji{{end}}", {{- if .BootstrapIDs }} "bootstrap-ids": "{{ .BootstrapIDs }}", @@ -12,6 +13,9 @@ {{- if .GenesisPath }} "genesis-file": "{{ .GenesisPath }}", {{- end }} +{{- if .UpgradePath }} + "upgrade-file": "{{ .UpgradePath }}", +{{- end }} {{- if .PublicIP }} "public-ip": "{{.PublicIP}}", {{- else }} diff --git a/pkg/ssh/ssh.go b/pkg/ssh/ssh.go index 7c2f1d486..325bc7ccd 100644 --- a/pkg/ssh/ssh.go +++ b/pkg/ssh/ssh.go @@ -429,6 +429,13 @@ func RunSSHSetupDevNet(host *models.Host, nodeInstanceDirPath string) error { ); err != nil { return err } + if err := host.Upload( + filepath.Join(nodeInstanceDirPath, constants.UpgradeFileName), + filepath.Join(constants.CloudNodeConfigPath, constants.UpgradeFileName), + constants.SSHFileOpsTimeout, + ); err != nil { + return err + } if err := host.Upload( filepath.Join(nodeInstanceDirPath, constants.NodeFileName), filepath.Join(constants.CloudNodeConfigPath, constants.NodeFileName), @@ -555,6 +562,9 @@ func RunSSHRenderAvalancheNodeConfig( if genesisFileExists(host) { avagoConf.GenesisPath = filepath.Join(constants.DockerNodeConfigPath, constants.GenesisFileName) } + if upgradeFileExists(host) { + avagoConf.UpgradePath = filepath.Join(constants.DockerNodeConfigPath, constants.UpgradeFileName) + } if network.Kind == models.Local || network.Kind == models.Devnet || isAPIHost { avagoConf.HTTPHost = "0.0.0.0" } @@ -898,6 +908,11 @@ func genesisFileExists(host *models.Host) bool { return genesisFileExists } +func upgradeFileExists(host *models.Host) bool { + upgradeFileExists, _ := host.FileExists(filepath.Join(constants.CloudNodeConfigPath, constants.UpgradeFileName)) + return upgradeFileExists +} + func nodeConfigFileExists(host *models.Host) bool { nodeConfigFileExists, _ := host.FileExists(remoteconfig.GetRemoteAvalancheNodeConfig()) return nodeConfigFileExists diff --git a/pkg/subnet/public.go b/pkg/subnet/public.go index f7c26e75d..3f717f723 100644 --- a/pkg/subnet/public.go +++ b/pkg/subnet/public.go @@ -9,10 +9,13 @@ import ( "time" "github.com/ava-labs/avalanchego/vms/platformvm/fx" + avagofee "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/platformvm/signer" + goethereumcommon "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" @@ -36,6 +39,8 @@ import ( "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" ) +const showFees = true + var ErrNoSubnetAuthKeysInWallet = errors.New("auth wallet does not contain subnet auth keys") type PublicDeployer struct { @@ -383,6 +388,7 @@ func (d *PublicDeployer) ConvertL1( subnetAuthKeysStrs []string, subnetID ids.ID, chainID ids.ID, + validatorManagerAddress goethereumcommon.Address, validators []*txs.ConvertSubnetValidator, ) (bool, ids.ID, *txs.Tx, []string, error) { ux.Logger.PrintToUser("Now calling ConvertL1 Tx...") @@ -399,8 +405,7 @@ func (d *PublicDeployer) ConvertL1( showLedgerSignatureMsg(d.kc.UsesLedger, d.kc.HasOnlyOneKey(), "ConvertL1 transaction") - var validatorManagerAddress []byte - tx, err := d.createConvertL1Tx(subnetAuthKeys, subnetID, chainID, validatorManagerAddress, validators, wallet) + tx, err := d.createConvertL1Tx(subnetAuthKeys, subnetID, chainID, validatorManagerAddress.Bytes(), validators, wallet) if err != nil { return false, ids.Empty, nil, nil, err } @@ -422,6 +427,43 @@ func (d *PublicDeployer) ConvertL1( return isFullySigned, id, tx, remainingSubnetAuthKeys, nil } +func (d *PublicDeployer) PChainTransfer( + destination ids.ShortID, + amount uint64, +) (ids.ID, *txs.Tx, error) { + wallet, err := d.loadCacheWallet() + if err != nil { + return ids.Empty, nil, err + } + to := secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{destination}, + } + output := &avax.TransferableOutput{ + Asset: avax.Asset{ID: wallet.P().Builder().Context().AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: amount, + OutputOwners: to, + }, + } + outputs := []*avax.TransferableOutput{output} + unsignedTx, err := wallet.P().Builder().NewBaseTx( + outputs, + ) + if err != nil { + return ids.Empty, nil, err + } + tx := txs.Tx{Unsigned: unsignedTx} + if err := wallet.P().Signer().Sign(context.Background(), &tx); err != nil { + return ids.Empty, nil, err + } + id, err := d.Commit(&tx, true) + if err != nil { + return ids.Empty, nil, err + } + return id, &tx, nil +} + func (d *PublicDeployer) Commit( tx *txs.Tx, waitForTxAcceptance bool, @@ -455,7 +497,7 @@ func (d *PublicDeployer) Commit( time.Sleep(sleepBetweenRepeats) } if issueTxErr != nil { - d.cleanCacheWallet() + d.CleanCacheWallet() } return tx.ID(), issueTxErr } @@ -509,7 +551,7 @@ func (d *PublicDeployer) loadWallet(subnetIDs ...ids.ID) (primary.Wallet, error) return wallet, nil } -func (d *PublicDeployer) cleanCacheWallet() { +func (d *PublicDeployer) CleanCacheWallet() { d.wallet = nil } @@ -561,6 +603,11 @@ func (d *PublicDeployer) createBlockchainTx( if err != nil { return nil, fmt.Errorf("error building tx: %w", err) } + if unsignedTx != nil { + if err := printFee("CreateChainTx", wallet, unsignedTx); err != nil { + return nil, err + } + } tx := txs.Tx{Unsigned: unsignedTx} // sign with current wallet if err := wallet.P().Signer().Sign(context.Background(), &tx); err != nil { @@ -577,7 +624,27 @@ func (d *PublicDeployer) createConvertL1Tx( validators []*txs.ConvertSubnetValidator, wallet primary.Wallet, ) (*txs.Tx, error) { - return nil, nil + options := d.getMultisigTxOptions(subnetAuthKeys) + unsignedTx, err := wallet.P().Builder().NewConvertSubnetTx( + subnetID, + chainID, + address, + validators, + options..., + ) + if err != nil { + return nil, fmt.Errorf("error building tx: %w", err) + } + if unsignedTx != nil { + if err := printFee("ConvertSubnetTX", wallet, unsignedTx); err != nil { + return nil, err + } + } + tx := txs.Tx{Unsigned: unsignedTx} + if err := wallet.P().Signer().Sign(context.Background(), &tx); err != nil { + return nil, fmt.Errorf("error signing tx: %w", err) + } + return &tx, nil } func (d *PublicDeployer) createTransferSubnetOwnershipTx( @@ -764,6 +831,11 @@ func (d *PublicDeployer) createSubnetTx(controlKeys []string, threshold uint32, unsignedTx, err := wallet.P().Builder().NewCreateSubnetTx( owners, ) + if unsignedTx != nil { + if err := printFee("CreateSubnetTx", wallet, unsignedTx); err != nil { + return ids.Empty, err + } + } if err != nil { return ids.Empty, fmt.Errorf("error building tx: %w", err) } @@ -775,6 +847,31 @@ func (d *PublicDeployer) createSubnetTx(controlKeys []string, threshold uint32, return d.Commit(&tx, true) } +func printFee(kind string, wallet primary.Wallet, unsignedTx txs.UnsignedTx) error { + if showFees { + var pFeeCalculator avagofee.Calculator + pContext := wallet.P().Builder().Context() + calcKind := "dynamic" + if pContext.GasPrice != 0 { + pFeeCalculator = avagofee.NewDynamicCalculator(pContext.ComplexityWeights, pContext.GasPrice) + } else { + pFeeCalculator = avagofee.NewStaticCalculator(pContext.StaticFeeConfig) + calcKind = "static" + } + txFee, err := pFeeCalculator.CalculateFee(unsignedTx) + if err != nil { + if errors.Is(err, avagofee.ErrUnsupportedTx) { + ux.Logger.PrintToUser(logging.Yellow.Wrap("unable to get %s fee: not supported by %s calculator"), kind, calcKind) + } else { + return err + } + } else { + ux.Logger.PrintToUser(logging.Yellow.Wrap("%s fee: %.9f AVAX"), kind, float64(txFee)/float64(units.Avax)) + } + } + return nil +} + func (d *PublicDeployer) getSubnetAuthAddressesInWallet(subnetAuth []ids.ShortID) []ids.ShortID { walletAddrs := d.kc.Addresses().List() subnetAuthInWallet := []ids.ShortID{} diff --git a/pkg/ux/progressbar.go b/pkg/ux/progressbar.go new file mode 100644 index 000000000..90362654b --- /dev/null +++ b/pkg/ux/progressbar.go @@ -0,0 +1,47 @@ +// Copyright (C) 2022, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. +package ux + +import ( + "fmt" + "time" + + ansi "github.com/k0kubun/go-ansi" + progressbar "github.com/schollz/progressbar/v3" +) + +func TimedProgressBar( + duration time.Duration, + title string, + extraSteps int, +) (*progressbar.ProgressBar, error) { + const steps = 1000 + stepDuration := duration / steps + bar := progressbar.NewOptions(steps+extraSteps, + progressbar.OptionSetWriter(ansi.NewAnsiStdout()), + progressbar.OptionEnableColorCodes(true), + progressbar.OptionSetElapsedTime(false), + progressbar.OptionSetWidth(15), + progressbar.OptionSetDescription(title), + progressbar.OptionSetTheme(progressbar.Theme{ + Saucer: "[green]=[reset]", + SaucerHead: "[green]>[reset]", + SaucerPadding: " ", + BarStart: "[", + BarEnd: "]", + })) + for i := 0; i < steps; i++ { + if err := bar.Add(1); err != nil { + return nil, err + } + time.Sleep(stepDuration) + } + if extraSteps == 0 { + fmt.Println() + } + return bar, nil +} + +func ExtraStepExecuted(bar *progressbar.ProgressBar) error { + return bar.Add(1) +} diff --git a/pkg/ux/spinner.go b/pkg/ux/spinner.go index 49e3f732e..c9cf17f33 100644 --- a/pkg/ux/spinner.go +++ b/pkg/ux/spinner.go @@ -11,6 +11,7 @@ import ( "github.com/chelnak/ysmrr" "github.com/chelnak/ysmrr/pkg/animations" "github.com/chelnak/ysmrr/pkg/colors" + ansi "github.com/k0kubun/go-ansi" ) type UserSpinner struct { @@ -55,6 +56,7 @@ func (us *UserSpinner) SpinToUser(msg string, args ...interface{}) *ysmrr.Spinne } func SpinFailWithError(s *ysmrr.Spinner, txt string, err error) { + ansi.CursorShow() if txt == "" { s.ErrorWithMessagef("%s err:%v", s.GetMessage(), err) } else { diff --git a/pkg/validatormanager/validatormanager.go b/pkg/validatormanager/validatormanager.go index e71e38d4f..05f61f80b 100644 --- a/pkg/validatormanager/validatormanager.go +++ b/pkg/validatormanager/validatormanager.go @@ -10,6 +10,7 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/application" "github.com/ava-labs/avalanche-cli/pkg/contract" + "github.com/ava-labs/avalanche-cli/pkg/evm" "github.com/ava-labs/avalanche-cli/pkg/models" "github.com/ava-labs/avalanche-cli/sdk/interchain" "github.com/ava-labs/avalanchego/ids" @@ -133,7 +134,7 @@ func PoaValidatorManagerGetPChainSubnetConversionWarpMessage( } subnetConversionUnsignedMessage, err := warp.NewUnsignedMessage( network.ID, - avagoconstants.PlatformChainID, // p-chain sign + avagoconstants.PlatformChainID, subnetConversionAddressedCall.Bytes(), ) if err != nil { @@ -143,13 +144,13 @@ func PoaValidatorManagerGetPChainSubnetConversionWarpMessage( network, aggregatorLogger, aggregatorLogLevel, - ids.Empty, // primary network validators sign + subnetID, aggregatorQuorumPercentage, ) if err != nil { return nil, err } - return signatureAggregator.Sign(subnetConversionUnsignedMessage, nil) + return signatureAggregator.Sign(subnetConversionUnsignedMessage, subnetID[:]) } // calls poa manager validators set init method, @@ -210,19 +211,16 @@ func PoAValidatorManagerInitializeValidatorsSet( func SetupPoA( app *application.Avalanche, network models.Network, + rpcURL string, chainSpec contract.ChainSpec, privateKey string, ownerAddress common.Address, convertSubnetValidators []*txs.ConvertSubnetValidator, ) error { - rpcURL, _, err := contract.GetBlockchainEndpoints( - app, - network, - chainSpec, - true, - false, - ) - if err != nil { + if err := evm.SetupProposerVM( + rpcURL, + privateKey, + ); err != nil { return err } subnetID, err := contract.GetSubnetID( @@ -275,7 +273,7 @@ func SetupPoA( subnetConversionSignedMessage, ) if err != nil { - return TransactionError(tx, err, "failure initializing validators set on poa manager") + return TransactionError(tx, err, "failure initializing validators set on poa manager") } return nil } diff --git a/pkg/vm/precompiles.go b/pkg/vm/precompiles.go index ee32c5a64..6bd199831 100644 --- a/pkg/vm/precompiles.go +++ b/pkg/vm/precompiles.go @@ -99,7 +99,8 @@ func configureRewardManager( func configureWarp(timestamp *uint64) warp.Config { return warp.Config{ - QuorumNumerator: warp.WarpDefaultQuorumNumerator, + QuorumNumerator: warp.WarpDefaultQuorumNumerator, + RequirePrimaryNetworkSigners: true, Upgrade: precompileconfig.Upgrade{ BlockTimestamp: timestamp, }, diff --git a/scripts/regenerate_mocks.sh b/scripts/regenerate_mocks.sh index 6537a1d31..f94eee0a7 100755 --- a/scripts/regenerate_mocks.sh +++ b/scripts/regenerate_mocks.sh @@ -14,11 +14,11 @@ if ! [[ "$0" =~ scripts/regenerate_mocks.sh ]]; then exit 1 fi -go install github.com/vektra/mockery/v2@latest +go install github.com/vektra/mockery/v2@v2.43.2 -mockery -r --output ./internal/mocks --name BinaryChecker --filename binaryChecker.go -mockery -r --output ./internal/mocks --name PluginBinaryDownloader --filename pluginBinaryDownloader.go -mockery -r --output ./internal/mocks --name ProcessChecker --filename processChecker.go +mockery -r --output ./internal/mocks --name BinaryChecker --filename binary_checker.go +mockery -r --output ./internal/mocks --name PluginBinaryDownloader --filename plugin_binary_downloader.go +mockery -r --output ./internal/mocks --name ProcessChecker --filename process_checker.go mockery -r --output ./internal/mocks --name Prompter --filename prompter.go mockery -r --output ./internal/mocks --name Installer --filename installer.go mockery -r --output ./internal/mocks --name Publisher --filename publisher.go diff --git a/tests/e2e/testcases/upgrade/non-sov/suite.go b/tests/e2e/testcases/upgrade/non-sov/suite.go index 081bf1e70..7bddda8a9 100644 --- a/tests/e2e/testcases/upgrade/non-sov/suite.go +++ b/tests/e2e/testcases/upgrade/non-sov/suite.go @@ -135,7 +135,7 @@ var _ = ginkgo.Describe("[Upgrade public network non SOV]", ginkgo.Ordered, func // we expect the file to be present at the expected location and being // the same content as the original one - expectedPath := filepath.Join(avalanchegoConfigDir, blockchainID.String(), constants.UpgradeBytesFileName) + expectedPath := filepath.Join(avalanchegoConfigDir, blockchainID.String(), constants.UpgradeFileName) gomega.Expect(expectedPath).Should(gomega.BeARegularFile()) ori, err := os.ReadFile(upgradeBytesPath) gomega.Expect(err).Should(gomega.BeNil()) diff --git a/tests/e2e/testcases/upgrade/sov/suite.go b/tests/e2e/testcases/upgrade/sov/suite.go index 381199953..b23f86362 100644 --- a/tests/e2e/testcases/upgrade/sov/suite.go +++ b/tests/e2e/testcases/upgrade/sov/suite.go @@ -135,7 +135,7 @@ var _ = ginkgo.Describe("[Upgrade public network SOV]", ginkgo.Ordered, func() { // we expect the file to be present at the expected location and being // the same content as the original one - expectedPath := filepath.Join(avalanchegoConfigDir, blockchainID.String(), constants.UpgradeBytesFileName) + expectedPath := filepath.Join(avalanchegoConfigDir, blockchainID.String(), constants.UpgradeFileName) gomega.Expect(expectedPath).Should(gomega.BeARegularFile()) ori, err := os.ReadFile(upgradeBytesPath) gomega.Expect(err).Should(gomega.BeNil())