From 2a622497695d6be67f0d180aa50e87c8d22d7df7 Mon Sep 17 00:00:00 2001 From: arturrez Date: Mon, 25 Nov 2024 08:56:35 -0800 Subject: [PATCH 01/31] wip --- cmd/blockchaincmd/remove_validator.go | 8 ++- pkg/validatormanager/removal.go | 78 ++++++++++++++++++++++++--- 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/cmd/blockchaincmd/remove_validator.go b/cmd/blockchaincmd/remove_validator.go index d3990e2d1..d256ba3cb 100644 --- a/cmd/blockchaincmd/remove_validator.go +++ b/cmd/blockchaincmd/remove_validator.go @@ -36,6 +36,10 @@ var removeValidatorSupportedNetworkOptions = []networkoptions.NetworkOption{ networkoptions.EtnaDevnet, } +var ( + uptimeSec uint64 +) + // avalanche blockchain removeValidator func newRemoveValidatorCmd() *cobra.Command { cmd := &cobra.Command{ @@ -61,6 +65,7 @@ these prompts by providing the values with flags.`, privateKeyFlags.AddToCmd(cmd, "to pay fees for completing the validator's removal (blockchain gas token)") cmd.Flags().StringVar(&rpcURL, "rpc", "", "connect to validator manager at the given rpc endpoint") cmd.Flags().StringVar(&aggregatorLogLevel, "aggregator-log-level", "Off", "log level to use with signature aggregator") + cmd.Flags().Uint64Var(&uptimeSec, "uptime", 0, "validator's uptime in seconds. If not provided, it will be automatically calculated") return cmd } @@ -183,7 +188,7 @@ func removeValidator(_ *cobra.Command, args []string) error { return false }) force := len(filteredBootstrapValidators) > 0 - if err := removeValidatorSOV(deployer, network, blockchainName, nodeID, force); err != nil { + if err := removeValidatorSOV(deployer, network, blockchainName, nodeID, uptimeSec, force); err != nil { return err } // remove the validator from the list of bootstrap validators @@ -207,6 +212,7 @@ func removeValidatorSOV( network models.Network, blockchainName string, nodeID ids.NodeID, + uptimeSec uint64, force bool, ) error { chainSpec := contract.ChainSpec{ diff --git a/pkg/validatormanager/removal.go b/pkg/validatormanager/removal.go index 0af6a0d74..ba0dd37b0 100644 --- a/pkg/validatormanager/removal.go +++ b/pkg/validatormanager/removal.go @@ -21,6 +21,7 @@ import ( warpMessage "github.com/ava-labs/avalanchego/vms/platformvm/warp/message" warpPayload "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" "github.com/ava-labs/subnet-evm/core/types" + "github.com/ava-labs/subnet-evm/warp/messages" "github.com/ethereum/go-ethereum/common" ) @@ -66,7 +67,46 @@ func ValidatorManagerInitializeValidatorRemoval( ) } -func ValidatorManagerGetSubnetValidatorWeightMessage( +func GetUptimeProofMessage( + network models.Network, + aggregatorLogLevel logging.Level, + aggregatorQuorumPercentage uint64, + aggregatorExtraPeerEndpoints []info.Peer, + subnetID ids.ID, + blockchainID ids.ID, + validationID ids.ID, + uptime uint64, +) (*warp.Message, error) { + uptimePayload, err := messages.NewValidatorUptime(validationID, uptime) + if err != nil { + return nil, err + } + addressedCall, err := warpPayload.NewAddressedCall(nil, uptimePayload.Bytes()) + if err != nil { + return nil, err + } + uptimeProofUnsignedMessage, err := warp.NewUnsignedMessage( + network.ID, + blockchainID, + addressedCall.Bytes(), + ) + if err != nil { + return nil, err + } + signatureAggregator, err := interchain.NewSignatureAggregator( + network, + aggregatorLogLevel, + subnetID, + aggregatorQuorumPercentage, + aggregatorExtraPeerEndpoints, + ) + if err != nil { + return nil, err + } + return signatureAggregator.Sign(uptimeProofUnsignedMessage, nil) +} + +func GetSubnetValidatorWeightMessage( network models.Network, aggregatorLogLevel logging.Level, aggregatorQuorumPercentage uint64, @@ -124,6 +164,7 @@ func InitValidatorRemoval( aggregatorExtraPeerEndpoints []info.Peer, aggregatorLogLevelStr string, initWithPos bool, + uptimeSec uint64, force bool, ) (*warp.Message, ids.ID, error) { subnetID, err := contract.GetSubnetID( @@ -152,7 +193,36 @@ func InitValidatorRemoval( return nil, ids.Empty, err } ux.Logger.PrintToUser("Using validationID: %s for nodeID: %s", validationID, nodeID) - tx, _, err := ValidatorManagerInitializeValidatorRemoval( + + aggregatorLogLevel, err := logging.ToLevel(aggregatorLogLevelStr) + if err != nil { + aggregatorLogLevel = defaultAggregatorLogLevel + } + + var uptimeProof *warp.Message + if initWithPos { + if up + uptimeSec, err := GetUptimeData() + if err != nil { + return nil, ids.Empty, evm.TransactionError(nil, err, "failure getting uptime data") + } + ux.Logger.PrintToUser("Using uptime: %d", uptimeSec) + + uptimeProof, err = GetUptimeProofMessage( + network, + aggregatorLogLevel, + 0, + aggregatorExtraPeerEndpoints, + subnetID, + blockchainID, + validationID, + 0, + ) + if err != nil { + return nil, ids.Empty, evm.TransactionError(nil, err, "failure getting uptime proof") + } + } + tx, _, err := InitializeValidatorRemoval( rpcURL, managerAddress, ownerPrivateKey, @@ -167,10 +237,6 @@ func InitValidatorRemoval( ux.Logger.PrintToUser("the validator removal process was already initialized. Proceeding to the next step") } - aggregatorLogLevel, err := logging.ToLevel(aggregatorLogLevelStr) - if err != nil { - aggregatorLogLevel = defaultAggregatorLogLevel - } nonce := uint64(1) signedMsg, err := ValidatorManagerGetSubnetValidatorWeightMessage( network, From a670cff7ba82e0b8fac9521b2e9eb145e08ce76b Mon Sep 17 00:00:00 2001 From: arturrez Date: Mon, 25 Nov 2024 14:22:05 -0800 Subject: [PATCH 02/31] rename funcs add warp msg for uptime proof --- pkg/validatormanager/registration.go | 20 ++++++++++---------- pkg/validatormanager/removal.go | 19 +++++++++---------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/pkg/validatormanager/registration.go b/pkg/validatormanager/registration.go index b734d0bf8..e35148ec3 100644 --- a/pkg/validatormanager/registration.go +++ b/pkg/validatormanager/registration.go @@ -32,7 +32,7 @@ import ( "google.golang.org/protobuf/proto" ) -func NativePoSValidatorManagerInitializeValidatorRegistration( +func InitializeValidatorRegistrationPoSNative( rpcURL string, managerAddress common.Address, managerOwnerPrivateKey string, @@ -93,7 +93,7 @@ func NativePoSValidatorManagerInitializeValidatorRegistration( } // step 1 of flow for adding a new validator -func PoAValidatorManagerInitializeValidatorRegistration( +func InitializeValidatorRegistrationPoA( rpcURL string, managerAddress common.Address, managerOwnerPrivateKey string, @@ -147,7 +147,7 @@ func PoAValidatorManagerInitializeValidatorRegistration( ) } -func ValidatorManagerGetSubnetValidatorRegistrationMessage( +func GetSubnetValidatorRegistrationMessage( network models.Network, aggregatorLogLevel logging.Level, aggregatorQuorumPercentage uint64, @@ -246,7 +246,7 @@ func GetValidatorWeight( return weight, nil } -func ValidatorManagerGetPChainSubnetValidatorRegistrationWarpMessage( +func GetPChainSubnetValidatorRegistrationWarpMessage( network models.Network, rpcURL string, aggregatorLogLevel logging.Level, @@ -296,7 +296,7 @@ func ValidatorManagerGetPChainSubnetValidatorRegistrationWarpMessage( } // last step of flow for adding a new validator -func ValidatorManagerCompleteValidatorRegistration( +func CompleteValidatorRegistration( rpcURL string, managerAddress common.Address, privateKey string, // not need to be owner atm @@ -357,7 +357,7 @@ func InitValidatorRegistration( ux.Logger.PrintToUser("Using rpcURL: %s", rpcURL) ux.Logger.PrintToUser("NodeID: %s staking %s for %ds", nodeID.String(), stakeAmount, uint64(stakeDuration.Seconds())) ux.Logger.PrintLineSeparator() - tx, _, err := NativePoSValidatorManagerInitializeValidatorRegistration( + tx, _, err := InitializeValidatorRegistrationPoSNative( rpcURL, managerAddress, ownerPrivateKey, @@ -378,7 +378,7 @@ func InitValidatorRegistration( } } else { managerAddress = common.HexToAddress(validatorManagerSDK.ProxyContractAddress) - tx, _, err := PoAValidatorManagerInitializeValidatorRegistration( + tx, _, err := InitializeValidatorRegistrationPoA( rpcURL, managerAddress, ownerPrivateKey, @@ -414,7 +414,7 @@ func InitValidatorRegistration( } ux.Logger.PrintToUser(fmt.Sprintf("Validator weight: %d", weight)) - return ValidatorManagerGetSubnetValidatorRegistrationMessage( + return GetSubnetValidatorRegistrationMessage( network, aggregatorLogLevel, 0, @@ -454,7 +454,7 @@ func FinishValidatorRegistration( aggregatorLogLevel = defaultAggregatorLogLevel } managerAddress := common.HexToAddress(validatorManagerSDK.ProxyContractAddress) - signedMessage, err := ValidatorManagerGetPChainSubnetValidatorRegistrationWarpMessage( + signedMessage, err := GetPChainSubnetValidatorRegistrationWarpMessage( network, rpcURL, aggregatorLogLevel, @@ -473,7 +473,7 @@ func FinishValidatorRegistration( ); err != nil { return err } - tx, _, err := ValidatorManagerCompleteValidatorRegistration( + tx, _, err := CompleteValidatorRegistration( rpcURL, managerAddress, privateKey, diff --git a/pkg/validatormanager/removal.go b/pkg/validatormanager/removal.go index ba0dd37b0..ee3d3d005 100644 --- a/pkg/validatormanager/removal.go +++ b/pkg/validatormanager/removal.go @@ -22,10 +22,11 @@ import ( warpPayload "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/warp/messages" + "github.com/ava-labs/teleporter/tests/interfaces" "github.com/ethereum/go-ethereum/common" ) -func ValidatorManagerInitializeValidatorRemoval( +func InitializeValidatorRemoval( rpcURL string, managerAddress common.Address, ownerPrivateKey string, @@ -34,9 +35,7 @@ func ValidatorManagerInitializeValidatorRemoval( force bool, ) (*types.Transaction, *types.Receipt, error) { if isPoS { - // PoS only supports forcefull removal //TODO: implement uptime proof to remove this restriction - // posEndValidation := "initializeEndValidation(bytes32,bool,uint32)" - posEndValidation := "forceInitializeEndValidation(bytes32,bool,uint32)" + posEndValidation := "initializeEndValidation(bytes32,bool,uint32)" if force { posEndValidation = "forceInitializeEndValidation(bytes32,bool,uint32)" } @@ -73,9 +72,9 @@ func GetUptimeProofMessage( aggregatorQuorumPercentage uint64, aggregatorExtraPeerEndpoints []info.Peer, subnetID ids.ID, - blockchainID ids.ID, validationID ids.ID, uptime uint64, + subnet interfaces.SubnetTestInfo, ) (*warp.Message, error) { uptimePayload, err := messages.NewValidatorUptime(validationID, uptime) if err != nil { @@ -87,7 +86,7 @@ func GetUptimeProofMessage( } uptimeProofUnsignedMessage, err := warp.NewUnsignedMessage( network.ID, - blockchainID, + subnet.BlockchainID, addressedCall.Bytes(), ) if err != nil { @@ -238,7 +237,7 @@ func InitValidatorRemoval( } nonce := uint64(1) - signedMsg, err := ValidatorManagerGetSubnetValidatorWeightMessage( + signedMsg, err := GetSubnetValidatorWeightMessage( network, aggregatorLogLevel, 0, @@ -253,7 +252,7 @@ func InitValidatorRemoval( return signedMsg, validationID, err } -func ValidatorManagerCompleteValidatorRemoval( +func CompleteValidatorRemoval( rpcURL string, managerAddress common.Address, privateKey string, // not need to be owner atm @@ -295,7 +294,7 @@ func FinishValidatorRemoval( if err != nil { aggregatorLogLevel = defaultAggregatorLogLevel } - signedMessage, err := ValidatorManagerGetPChainSubnetValidatorRegistrationWarpMessage( + signedMessage, err := GetPChainSubnetValidatorRegistrationWarpMessage( network, rpcURL, aggregatorLogLevel, @@ -314,7 +313,7 @@ func FinishValidatorRemoval( ); err != nil { return err } - tx, _, err := ValidatorManagerCompleteValidatorRemoval( + tx, _, err := CompleteValidatorRemoval( rpcURL, managerAddress, privateKey, From 140138c76135d9bc14aa67b33e87b05076aed26e Mon Sep 17 00:00:00 2001 From: arturrez Date: Mon, 25 Nov 2024 14:29:55 -0800 Subject: [PATCH 03/31] code cleanup --- cmd/blockchaincmd/change_weight.go | 1 + cmd/blockchaincmd/remove_validator.go | 1 + pkg/validatormanager/removal.go | 16 ++++++++++------ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/cmd/blockchaincmd/change_weight.go b/cmd/blockchaincmd/change_weight.go index a3fb5a949..4f349569a 100644 --- a/cmd/blockchaincmd/change_weight.go +++ b/cmd/blockchaincmd/change_weight.go @@ -152,6 +152,7 @@ func setWeight(_ *cobra.Command, args []string) error { network, blockchainName, nodeID, + 0, // automatic uptime false, // don't force ) if err != nil { diff --git a/cmd/blockchaincmd/remove_validator.go b/cmd/blockchaincmd/remove_validator.go index d256ba3cb..4ebc9c5d9 100644 --- a/cmd/blockchaincmd/remove_validator.go +++ b/cmd/blockchaincmd/remove_validator.go @@ -269,6 +269,7 @@ func removeValidatorSOV( extraAggregatorPeers, aggregatorLogLevel, sc.PoS(), + uptimeSec, force, ) if err != nil { diff --git a/pkg/validatormanager/removal.go b/pkg/validatormanager/removal.go index ee3d3d005..d282de08c 100644 --- a/pkg/validatormanager/removal.go +++ b/pkg/validatormanager/removal.go @@ -22,7 +22,6 @@ import ( warpPayload "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/warp/messages" - "github.com/ava-labs/teleporter/tests/interfaces" "github.com/ethereum/go-ethereum/common" ) @@ -72,9 +71,9 @@ func GetUptimeProofMessage( aggregatorQuorumPercentage uint64, aggregatorExtraPeerEndpoints []info.Peer, subnetID ids.ID, + blockchainID ids.ID, validationID ids.ID, uptime uint64, - subnet interfaces.SubnetTestInfo, ) (*warp.Message, error) { uptimePayload, err := messages.NewValidatorUptime(validationID, uptime) if err != nil { @@ -86,7 +85,7 @@ func GetUptimeProofMessage( } uptimeProofUnsignedMessage, err := warp.NewUnsignedMessage( network.ID, - subnet.BlockchainID, + blockchainID, addressedCall.Bytes(), ) if err != nil { @@ -200,8 +199,9 @@ func InitValidatorRemoval( var uptimeProof *warp.Message if initWithPos { - if up - uptimeSec, err := GetUptimeData() + if uptimeSec == 0 { + uptimeSec, err = GetUptimeData() + } if err != nil { return nil, ids.Empty, evm.TransactionError(nil, err, "failure getting uptime data") } @@ -215,7 +215,7 @@ func InitValidatorRemoval( subnetID, blockchainID, validationID, - 0, + uptimeSec, ) if err != nil { return nil, ids.Empty, evm.TransactionError(nil, err, "failure getting uptime proof") @@ -324,3 +324,7 @@ func FinishValidatorRemoval( } return nil } + +func GetUptimeData() (uint64, error) { + return 0, nil +} From d3607671980ba91404b3b95860ec0f7ea97eda93 Mon Sep 17 00:00:00 2001 From: arturrez Date: Tue, 26 Nov 2024 12:48:52 -0800 Subject: [PATCH 04/31] PoS validator removal with provided uptime --- cmd/blockchaincmd/add_validator.go | 20 +------- cmd/blockchaincmd/remove_validator.go | 4 +- pkg/utils/staking.go | 20 ++++++++ pkg/validatormanager/removal.go | 68 ++++++++++++++++++--------- 4 files changed, 69 insertions(+), 43 deletions(-) diff --git a/cmd/blockchaincmd/add_validator.go b/cmd/blockchaincmd/add_validator.go index ada28db60..69b40f77f 100644 --- a/cmd/blockchaincmd/add_validator.go +++ b/cmd/blockchaincmd/add_validator.go @@ -30,7 +30,6 @@ import ( avagoconstants "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/formatting/address" "github.com/ava-labs/avalanchego/utils/logging" - "github.com/ava-labs/avalanchego/vms/platformvm" warpMessage "github.com/ava-labs/avalanchego/vms/platformvm/warp/message" "github.com/spf13/cobra" ) @@ -584,23 +583,6 @@ func PromptDuration(start time.Time, network models.Network) (time.Duration, err } } -func getMaxValidationTime(network models.Network, nodeID ids.NodeID, startTime time.Time) (time.Duration, error) { - ctx, cancel := utils.GetAPIContext() - defer cancel() - platformCli := platformvm.NewClient(network.Endpoint) - vs, err := platformCli.GetCurrentValidators(ctx, avagoconstants.PrimaryNetworkID, nil) - cancel() - if err != nil { - return 0, err - } - for _, v := range vs { - if v.NodeID == nodeID { - return time.Unix(int64(v.EndTime), 0).Sub(startTime), nil - } - } - return 0, errors.New("nodeID not found in validator set: " + nodeID.String()) -} - func getTimeParameters(network models.Network, nodeID ids.NodeID, isValidator bool) (time.Time, time.Duration, error) { defaultStakingStartLeadTime := constants.StakingStartLeadTime if network.Kind == models.Devnet { @@ -679,7 +661,7 @@ func getTimeParameters(network models.Network, nodeID ids.NodeID, isValidator bo var selectedDuration time.Duration if useDefaultDuration { // avoid setting both globals useDefaultDuration and duration - selectedDuration, err = getMaxValidationTime(network, nodeID, start) + selectedDuration, err = utils.GetValidationTime(network.Endpoint, nodeID, avagoconstants.PrimaryNetworkID, start) if err != nil { return time.Time{}, 0, err } diff --git a/cmd/blockchaincmd/remove_validator.go b/cmd/blockchaincmd/remove_validator.go index 4ebc9c5d9..7bd84684c 100644 --- a/cmd/blockchaincmd/remove_validator.go +++ b/cmd/blockchaincmd/remove_validator.go @@ -36,9 +36,7 @@ var removeValidatorSupportedNetworkOptions = []networkoptions.NetworkOption{ networkoptions.EtnaDevnet, } -var ( - uptimeSec uint64 -) +var uptimeSec uint64 // avalanche blockchain removeValidator func newRemoveValidatorCmd() *cobra.Command { diff --git a/pkg/utils/staking.go b/pkg/utils/staking.go index 5df9d88a6..5da8e74de 100644 --- a/pkg/utils/staking.go +++ b/pkg/utils/staking.go @@ -4,14 +4,17 @@ package utils import ( "encoding/pem" + "errors" "fmt" "os" "path/filepath" + "time" "github.com/ava-labs/avalanche-cli/pkg/constants" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/staking" "github.com/ava-labs/avalanchego/utils/crypto/bls" + "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/signer" ) @@ -73,3 +76,20 @@ func GetNodeParams(nodeDir string) ( } return nodeID, blsPub, blsPoP, nil } + +func GetValidationTime(networkEndpoint string, nodeID ids.NodeID, subnetID ids.ID, startTime time.Time) (time.Duration, error) { + ctx, cancel := GetAPIContext() + defer cancel() + platformCli := platformvm.NewClient(networkEndpoint) + vs, err := platformCli.GetCurrentValidators(ctx, subnetID, nil) + cancel() + if err != nil { + return 0, err + } + for _, v := range vs { + if v.NodeID == nodeID { + return time.Unix(int64(v.EndTime), 0).Sub(startTime), nil + } + } + return 0, errors.New("nodeID not found in validator set: " + nodeID.String()) +} diff --git a/pkg/validatormanager/removal.go b/pkg/validatormanager/removal.go index d282de08c..e956a3c36 100644 --- a/pkg/validatormanager/removal.go +++ b/pkg/validatormanager/removal.go @@ -28,34 +28,68 @@ import ( func InitializeValidatorRemoval( rpcURL string, managerAddress common.Address, - ownerPrivateKey string, + privateKey string, validationID [32]byte, isPoS bool, + uptimeProofSignedMessage *warp.Message, force bool, ) (*types.Transaction, *types.Receipt, error) { if isPoS { - posEndValidation := "initializeEndValidation(bytes32,bool,uint32)" if force { - posEndValidation = "forceInitializeEndValidation(bytes32,bool,uint32)" + return contract.TxToMethod( + rpcURL, + privateKey, + managerAddress, + big.NewInt(0), + "force POS validator removal", + validatorManagerSDK.ErrorSignatureToError, + "forceInitializeEndValidation(bytes32,bool,uint32)", + validationID, + false, // no uptime proof if force + uint32(0), + ) + } + // provide uptime proof first via submit + if tx, receipt, err := contract.TxToMethodWithWarpMessage( + rpcURL, + privateKey, + managerAddress, + uptimeProofSignedMessage, + big.NewInt(0), + "POS validator removal with uptime proof", + validatorManagerSDK.ErrorSignatureToError, + "submitUptimeProof(bytes32,uint32)", + validationID, + uint32(0), + ); err != nil { + return nil, nil, evm.TransactionError(tx, err, "failure submitting uptime proof") + } else { + ux.Logger.PrintToUser("Uptime proof submitted with tx hash %s. status: %d Log: %d", tx.Hash().String(), receipt.Status, len(receipt.Logs)) + for _, log := range receipt.Logs { + ux.Logger.PrintToUser("Log: %s", log.Address) + ux.Logger.PrintToUser("Log: %s", log.Topics) + } } - return contract.TxToMethod( + // remove PoS validator with uptime proof + return contract.TxToMethodWithWarpMessage( rpcURL, - ownerPrivateKey, + privateKey, managerAddress, + uptimeProofSignedMessage, big.NewInt(0), - "POS validator removal initialization", + "POS validator removal with uptime proof", validatorManagerSDK.ErrorSignatureToError, - posEndValidation, + "initializeEndValidation(bytes32,bool,uint32)", validationID, - false, // don't include uptime proof - rely on network to calculate uptime + false, // uptime proof sibmited in previous step uint32(0), ) } // PoA case return contract.TxToMethod( rpcURL, - ownerPrivateKey, + privateKey, managerAddress, big.NewInt(0), "POA validator removal initialization", @@ -196,18 +230,13 @@ func InitValidatorRemoval( if err != nil { aggregatorLogLevel = defaultAggregatorLogLevel } - - var uptimeProof *warp.Message + signedUptimeProof := &warp.Message{} if initWithPos { - if uptimeSec == 0 { - uptimeSec, err = GetUptimeData() - } if err != nil { return nil, ids.Empty, evm.TransactionError(nil, err, "failure getting uptime data") } - ux.Logger.PrintToUser("Using uptime: %d", uptimeSec) - - uptimeProof, err = GetUptimeProofMessage( + ux.Logger.PrintToUser("Using uptime: %ds", uptimeSec) + signedUptimeProof, err = GetUptimeProofMessage( network, aggregatorLogLevel, 0, @@ -227,6 +256,7 @@ func InitValidatorRemoval( ownerPrivateKey, validationID, initWithPos, + signedUptimeProof, // is empty for non-PoS force, ) if err != nil { @@ -324,7 +354,3 @@ func FinishValidatorRemoval( } return nil } - -func GetUptimeData() (uint64, error) { - return 0, nil -} From 3610541ca3137ce0073bfb02954de3056aa86dbb Mon Sep 17 00:00:00 2001 From: arturrez Date: Tue, 26 Nov 2024 15:32:10 -0800 Subject: [PATCH 05/31] add uptimeproof r4r --- pkg/utils/net.go | 18 ++++ pkg/utils/net_test.go | 82 +++++++++++++++++-- pkg/utils/staking.go | 22 +++++ pkg/validatormanager/removal.go | 33 ++------ pkg/validatormanager/validatormanager.go | 2 + tests/e2e/commands/etna.go | 2 +- .../subnet/sov/addRemoveValidatorPoS/suite.go | 23 +++--- 7 files changed, 138 insertions(+), 44 deletions(-) diff --git a/pkg/utils/net.go b/pkg/utils/net.go index 408a79627..ad16f575b 100644 --- a/pkg/utils/net.go +++ b/pkg/utils/net.go @@ -5,11 +5,13 @@ package utils import ( "encoding/json" "errors" + "fmt" "io" "net" "net/http" "net/netip" "net/url" + "strings" ) // GetUserIPAddress retrieves the IP address of the user. @@ -65,3 +67,19 @@ func IsValidIPPort(ipPortPair string) bool { } return true } + +// SplitRPCURI splits the RPC URI into `endpoint` and `chain`. +// Reverse operation of `fmt.Sprintf("%s/ext/bc/%s", endpoint, chain)`. +// returns the `uri` and `chain` as strings, or an error if the request URI is invalid. +func SplitRPCURI(requestUri string) (string, string, error) { + // Check if the request URI contains "/ext/bc/" + splitPoint := "/ext/bc/" + index := strings.Index(requestUri, splitPoint) + if index == -1 { + return "", "", fmt.Errorf("invalid request URI format") + } + // Extract `uri` and `chain` + uri := requestUri[:index] + chain := requestUri[index+len(splitPoint):] + return uri, strings.TrimSuffix(chain, "/"), nil +} diff --git a/pkg/utils/net_test.go b/pkg/utils/net_test.go index 57a9d2a5b..fa8d6da63 100644 --- a/pkg/utils/net_test.go +++ b/pkg/utils/net_test.go @@ -11,13 +11,13 @@ func TestIsValidIPPort(t *testing.T) { input string expected bool }{ - {"127.0.0.1:8080", true}, // valid IP:port - {"256.0.0.1:8080", false}, // invalid IP address - {"example.com:8080", false}, // only ip address is allowed - {"127.0.0.1", false}, // missing port - {"[::1]:8080", true}, // valid IPv6 address - {"[::1]", false}, // missing port for IPv6 - {"", false}, // empty string + {"127.0.0.1:8080", true}, // valid IP:port + {"256.0.0.1:8080", false}, // invalid IP address + {"127.0.0.1:9650:8080", false}, // only ip address is allowed + {"127.0.0.1", false}, // missing port + {"[::1]:8080", true}, // valid IPv6 address + {"[::1]", false}, // missing port for IPv6 + {"", false}, // empty string } for _, test := range tests { @@ -29,3 +29,71 @@ func TestIsValidIPPort(t *testing.T) { }) } } + +func TestSplitRPCtURI(t *testing.T) { + tests := []struct { + name string + requestUri string + expectedURI string + expectedChain string + expectError bool + }{ + { + name: "Valid URI without trailing slash", + requestUri: "http://127.0.0.1:9650/ext/bc/mychain", + expectedURI: "http://127.0.0.1:9650", + expectedChain: "mychain", + expectError: false, + }, + { + name: "Valid URI with trailing slash", + requestUri: "http://127.0.0.1:9650/ext/bc/mychain/", + expectedURI: "http://127.0.0.1:9650", + expectedChain: "mychain", + expectError: false, + }, + { + name: "Invalid URI - missing /ext/bc/", + requestUri: "http://127.0.0.1:9650/mychain", + expectedURI: "", + expectedChain: "", + expectError: true, + }, + { + name: "Valid URI with no chain", + requestUri: "http://127.0.0.1:9650/ext/bc/", + expectedURI: "http://127.0.0.1:9650", + expectedChain: "", + expectError: false, + }, + { + name: "Valid URI with complex chain", + requestUri: "http://127.0.0.1:9650/ext/bc/mychain/extra", + expectedURI: "http://127.0.0.1:9650", + expectedChain: "mychain/extra", + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + uri, chain, err := SplitRPCURI(tt.requestUri) + + if tt.expectError { + if err == nil { + t.Errorf("expected an error but got nil") + } + } else { + if err != nil { + t.Errorf("did not expect an error but got: %v", err) + } + if uri != tt.expectedURI { + t.Errorf("expected URI: %s, got: %s", tt.expectedURI, uri) + } + if chain != tt.expectedChain { + t.Errorf("expected Chain: %s, got: %s", tt.expectedChain, chain) + } + } + }) + } +} diff --git a/pkg/utils/staking.go b/pkg/utils/staking.go index 5da8e74de..f85660b0f 100644 --- a/pkg/utils/staking.go +++ b/pkg/utils/staking.go @@ -16,6 +16,8 @@ import ( "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/signer" + + subnetEvmPlugin "github.com/ava-labs/subnet-evm/plugin/evm" ) func NewBlsSecretKeyBytes() ([]byte, error) { @@ -93,3 +95,23 @@ func GetValidationTime(networkEndpoint string, nodeID ids.NodeID, subnetID ids.I } return 0, errors.New("nodeID not found in validator set: " + nodeID.String()) } + +// GetL1ValidatorUptimeSeconds returns the uptime of the L1 validator +func GetL1ValidatorUptimeSeconds(rpcURL string, nodeID ids.NodeID) (uint64, error) { + ctx, cancel := GetAPIContext() + defer cancel() + networkEndpoint, blockchainID, err := SplitRPCURI(rpcURL) + if err != nil { + return 0, err + } + evmCli := subnetEvmPlugin.NewClient(networkEndpoint, blockchainID) + validators, err := evmCli.GetCurrentValidators(ctx, []ids.NodeID{nodeID}) + if err != nil { + return 0, err + } + if len(validators) > 0 { + return validators[0].UptimeSeconds, nil + } + + return 0, errors.New("nodeID not found in validator set: " + nodeID.String()) +} diff --git a/pkg/validatormanager/removal.go b/pkg/validatormanager/removal.go index e956a3c36..6e46edeaf 100644 --- a/pkg/validatormanager/removal.go +++ b/pkg/validatormanager/removal.go @@ -11,6 +11,7 @@ import ( "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/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" "github.com/ava-labs/avalanche-cli/sdk/interchain" validatorManagerSDK "github.com/ava-labs/avalanche-cli/sdk/validatormanager" @@ -29,7 +30,7 @@ func InitializeValidatorRemoval( rpcURL string, managerAddress common.Address, privateKey string, - validationID [32]byte, + validationID ids.ID, isPoS bool, uptimeProofSignedMessage *warp.Message, force bool, @@ -49,28 +50,6 @@ func InitializeValidatorRemoval( uint32(0), ) } - // provide uptime proof first via submit - if tx, receipt, err := contract.TxToMethodWithWarpMessage( - rpcURL, - privateKey, - managerAddress, - uptimeProofSignedMessage, - big.NewInt(0), - "POS validator removal with uptime proof", - validatorManagerSDK.ErrorSignatureToError, - "submitUptimeProof(bytes32,uint32)", - validationID, - uint32(0), - ); err != nil { - return nil, nil, evm.TransactionError(tx, err, "failure submitting uptime proof") - } else { - ux.Logger.PrintToUser("Uptime proof submitted with tx hash %s. status: %d Log: %d", tx.Hash().String(), receipt.Status, len(receipt.Logs)) - for _, log := range receipt.Logs { - ux.Logger.PrintToUser("Log: %s", log.Address) - ux.Logger.PrintToUser("Log: %s", log.Topics) - } - } - // remove PoS validator with uptime proof return contract.TxToMethodWithWarpMessage( rpcURL, @@ -82,7 +61,7 @@ func InitializeValidatorRemoval( validatorManagerSDK.ErrorSignatureToError, "initializeEndValidation(bytes32,bool,uint32)", validationID, - false, // uptime proof sibmited in previous step + true, // submit uptime proof uint32(0), ) } @@ -235,6 +214,12 @@ func InitValidatorRemoval( if err != nil { return nil, ids.Empty, evm.TransactionError(nil, err, "failure getting uptime data") } + if uptimeSec == 0 { + uptimeSec, err = utils.GetL1ValidatorUptimeSeconds(rpcURL, nodeID) + if err != nil { + return nil, ids.Empty, evm.TransactionError(nil, err, "failure getting uptime data for nodeID: %s via %s ", nodeID, rpcURL) + } + } ux.Logger.PrintToUser("Using uptime: %ds", uptimeSec) signedUptimeProof, err = GetUptimeProofMessage( network, diff --git a/pkg/validatormanager/validatormanager.go b/pkg/validatormanager/validatormanager.go index 8ec129cde..ea31c9112 100644 --- a/pkg/validatormanager/validatormanager.go +++ b/pkg/validatormanager/validatormanager.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/ava-labs/avalanche-cli/pkg/models" + "github.com/ava-labs/avalanche-cli/pkg/ux" blockchainSDK "github.com/ava-labs/avalanche-cli/sdk/blockchain" validatorManagerSDK "github.com/ava-labs/avalanche-cli/sdk/validatormanager" "github.com/ava-labs/avalanchego/api/info" @@ -90,6 +91,7 @@ func AddRewardCalculatorToAllocations( allocs core.GenesisAlloc, rewardBasisPoints uint64, ) { + ux.Logger.PrintToUser("Adding reward calculator contract to allocations %d", rewardBasisPoints) deployedRewardCalculatorBytes := common.FromHex(strings.TrimSpace(string(deployedRewardCalculatorBytecode))) allocs[common.HexToAddress(validatorManagerSDK.RewardCalculatorAddress)] = core.GenesisAccount{ Balance: big.NewInt(0), diff --git a/tests/e2e/commands/etna.go b/tests/e2e/commands/etna.go index 3caeb5d34..66a99c9a3 100644 --- a/tests/e2e/commands/etna.go +++ b/tests/e2e/commands/etna.go @@ -41,7 +41,7 @@ func CreateEtnaSubnetEvmConfig( rewardBasisPoints := "" subnetManagementStr := PoAString if subnetManagementType == PoS { - rewardBasisPoints = "--reward-basis-points=100" + rewardBasisPoints = "--reward-basis-points=10000000" subnetManagementStr = PoSString } // Create config diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go index c4a913ad2..cfc60b2b3 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go @@ -124,18 +124,17 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { time.Sleep(120 * time.Second) }) - /* - ginkgo.It("Can remove non-bootstrap validator", func() { - output, err := commands.RemoveEtnaSubnetValidatorFromCluster( - testLocalNodeName, - subnetName, - "http://127.0.0.1:9662", - keyName, - ) - gomega.Expect(err).Should(gomega.BeNil()) - fmt.Println(output) - }) - */ + ginkgo.It("Can remove non-bootstrap validator", func() { + output, err := commands.RemoveEtnaSubnetValidatorFromCluster( + testLocalNodeName, + subnetName, + "http://127.0.0.1:9662", + keyName, + ) + gomega.Expect(err).Should(gomega.BeNil()) + fmt.Println(output) + }) + ginkgo.It("Can remove bootstrap validator", func() { output, err := commands.RemoveEtnaSubnetValidatorFromCluster( testLocalNodeName, From 943827ff1c225d47f44d1075ca5b4f28d91a4aa3 Mon Sep 17 00:00:00 2001 From: arturrez Date: Tue, 26 Nov 2024 15:33:19 -0800 Subject: [PATCH 06/31] lint --- pkg/utils/net.go | 8 ++++---- pkg/utils/net_test.go | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pkg/utils/net.go b/pkg/utils/net.go index ad16f575b..dffc118c9 100644 --- a/pkg/utils/net.go +++ b/pkg/utils/net.go @@ -71,15 +71,15 @@ func IsValidIPPort(ipPortPair string) bool { // SplitRPCURI splits the RPC URI into `endpoint` and `chain`. // Reverse operation of `fmt.Sprintf("%s/ext/bc/%s", endpoint, chain)`. // returns the `uri` and `chain` as strings, or an error if the request URI is invalid. -func SplitRPCURI(requestUri string) (string, string, error) { +func SplitRPCURI(requestURI string) (string, string, error) { // Check if the request URI contains "/ext/bc/" splitPoint := "/ext/bc/" - index := strings.Index(requestUri, splitPoint) + index := strings.Index(requestURI, splitPoint) if index == -1 { return "", "", fmt.Errorf("invalid request URI format") } // Extract `uri` and `chain` - uri := requestUri[:index] - chain := requestUri[index+len(splitPoint):] + uri := requestURI[:index] + chain := requestURI[index+len(splitPoint):] return uri, strings.TrimSuffix(chain, "/"), nil } diff --git a/pkg/utils/net_test.go b/pkg/utils/net_test.go index fa8d6da63..316f612ef 100644 --- a/pkg/utils/net_test.go +++ b/pkg/utils/net_test.go @@ -33,42 +33,42 @@ func TestIsValidIPPort(t *testing.T) { func TestSplitRPCtURI(t *testing.T) { tests := []struct { name string - requestUri string + requestURI string expectedURI string expectedChain string expectError bool }{ { name: "Valid URI without trailing slash", - requestUri: "http://127.0.0.1:9650/ext/bc/mychain", + requestURI: "http://127.0.0.1:9650/ext/bc/mychain", expectedURI: "http://127.0.0.1:9650", expectedChain: "mychain", expectError: false, }, { name: "Valid URI with trailing slash", - requestUri: "http://127.0.0.1:9650/ext/bc/mychain/", + requestURI: "http://127.0.0.1:9650/ext/bc/mychain/", expectedURI: "http://127.0.0.1:9650", expectedChain: "mychain", expectError: false, }, { name: "Invalid URI - missing /ext/bc/", - requestUri: "http://127.0.0.1:9650/mychain", + requestURI: "http://127.0.0.1:9650/mychain", expectedURI: "", expectedChain: "", expectError: true, }, { name: "Valid URI with no chain", - requestUri: "http://127.0.0.1:9650/ext/bc/", + requestURI: "http://127.0.0.1:9650/ext/bc/", expectedURI: "http://127.0.0.1:9650", expectedChain: "", expectError: false, }, { name: "Valid URI with complex chain", - requestUri: "http://127.0.0.1:9650/ext/bc/mychain/extra", + requestURI: "http://127.0.0.1:9650/ext/bc/mychain/extra", expectedURI: "http://127.0.0.1:9650", expectedChain: "mychain/extra", expectError: false, @@ -77,7 +77,7 @@ func TestSplitRPCtURI(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - uri, chain, err := SplitRPCURI(tt.requestUri) + uri, chain, err := SplitRPCURI(tt.requestURI) if tt.expectError { if err == nil { From f35b55ad88f2bd5cafe913831c217a3871ed7a0f Mon Sep 17 00:00:00 2001 From: arturrez Date: Tue, 26 Nov 2024 16:08:36 -0800 Subject: [PATCH 07/31] lint, switch to regex, cleanup --- pkg/utils/net.go | 25 +++++++----- pkg/utils/net_test.go | 68 ++++++++++++++++----------------- pkg/validatormanager/removal.go | 1 - 3 files changed, 50 insertions(+), 44 deletions(-) diff --git a/pkg/utils/net.go b/pkg/utils/net.go index dffc118c9..6a480e9d1 100644 --- a/pkg/utils/net.go +++ b/pkg/utils/net.go @@ -11,7 +11,7 @@ import ( "net/http" "net/netip" "net/url" - "strings" + "regexp" ) // GetUserIPAddress retrieves the IP address of the user. @@ -71,15 +71,22 @@ func IsValidIPPort(ipPortPair string) bool { // SplitRPCURI splits the RPC URI into `endpoint` and `chain`. // Reverse operation of `fmt.Sprintf("%s/ext/bc/%s", endpoint, chain)`. // returns the `uri` and `chain` as strings, or an error if the request URI is invalid. +// SplitRPCURI splits the RPC URL into `endpoint` and `chain`. +// It matches the pattern `http:///ext/bc//rpc` using a regex. func SplitRPCURI(requestURI string) (string, string, error) { - // Check if the request URI contains "/ext/bc/" - splitPoint := "/ext/bc/" - index := strings.Index(requestURI, splitPoint) - if index == -1 { + // Define the regex pattern + pattern := `^(https?://[^/]+)/ext/bc/([^/]+)/rpc$` + regex := regexp.MustCompile(pattern) + + // Match the pattern + matches := regex.FindStringSubmatch(requestURI) + if matches == nil || len(matches) != 3 { return "", "", fmt.Errorf("invalid request URI format") } - // Extract `uri` and `chain` - uri := requestURI[:index] - chain := requestURI[index+len(splitPoint):] - return uri, strings.TrimSuffix(chain, "/"), nil + + // Extract `endpoint` and `chain` + endpoint := matches[1] + chain := matches[2] + + return endpoint, chain, nil } diff --git a/pkg/utils/net_test.go b/pkg/utils/net_test.go index 316f612ef..0863ca22d 100644 --- a/pkg/utils/net_test.go +++ b/pkg/utils/net_test.go @@ -30,54 +30,54 @@ func TestIsValidIPPort(t *testing.T) { } } -func TestSplitRPCtURI(t *testing.T) { +func TestSplitRPCURI(t *testing.T) { tests := []struct { - name string - requestURI string - expectedURI string - expectedChain string - expectError bool + name string + requestURI string + expectedEndpoint string + expectedChain string + expectError bool }{ { - name: "Valid URI without trailing slash", - requestURI: "http://127.0.0.1:9650/ext/bc/mychain", - expectedURI: "http://127.0.0.1:9650", - expectedChain: "mychain", - expectError: false, + name: "Valid URI", + requestURI: "http://127.0.0.1:9660/ext/bc/nL95ujcHLPFhuQdHYkvS3CSUvDr9EfZduzyJ5Ty6VXXMgyEEF/rpc", + expectedEndpoint: "http://127.0.0.1:9660", + expectedChain: "nL95ujcHLPFhuQdHYkvS3CSUvDr9EfZduzyJ5Ty6VXXMgyEEF", + expectError: false, }, { - name: "Valid URI with trailing slash", - requestURI: "http://127.0.0.1:9650/ext/bc/mychain/", - expectedURI: "http://127.0.0.1:9650", - expectedChain: "mychain", - expectError: false, + name: "Valid URI with https", + requestURI: "https://example.com:8080/ext/bc/testChain/rpc", + expectedEndpoint: "https://example.com:8080", + expectedChain: "testChain", + expectError: false, }, { - name: "Invalid URI - missing /ext/bc/", - requestURI: "http://127.0.0.1:9650/mychain", - expectedURI: "", - expectedChain: "", - expectError: true, + name: "Invalid URI - missing /rpc", + requestURI: "http://127.0.0.1:9660/ext/bc/nL95ujcHLPFhuQdHYkvS3CSUvDr9EfZduzyJ5Ty6VXXMgyEEF", + expectedEndpoint: "", + expectedChain: "", + expectError: true, }, { - name: "Valid URI with no chain", - requestURI: "http://127.0.0.1:9650/ext/bc/", - expectedURI: "http://127.0.0.1:9650", - expectedChain: "", - expectError: false, + name: "Invalid URI - missing /ext/bc/", + requestURI: "http://127.0.0.1:9660/some/other/path/rpc", + expectedEndpoint: "", + expectedChain: "", + expectError: true, }, { - name: "Valid URI with complex chain", - requestURI: "http://127.0.0.1:9650/ext/bc/mychain/extra", - expectedURI: "http://127.0.0.1:9650", - expectedChain: "mychain/extra", - expectError: false, + name: "Invalid URI - malformed URL", + requestURI: "127.0.0.1:9660/ext/bc/chainId/rpc", + expectedEndpoint: "", + expectedChain: "", + expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - uri, chain, err := SplitRPCURI(tt.requestURI) + endpoint, chain, err := SplitRPCURI(tt.requestURI) if tt.expectError { if err == nil { @@ -87,8 +87,8 @@ func TestSplitRPCtURI(t *testing.T) { if err != nil { t.Errorf("did not expect an error but got: %v", err) } - if uri != tt.expectedURI { - t.Errorf("expected URI: %s, got: %s", tt.expectedURI, uri) + if endpoint != tt.expectedEndpoint { + t.Errorf("expected Endpoint: %s, got: %s", tt.expectedEndpoint, endpoint) } if chain != tt.expectedChain { t.Errorf("expected Chain: %s, got: %s", tt.expectedChain, chain) diff --git a/pkg/validatormanager/removal.go b/pkg/validatormanager/removal.go index 6e46edeaf..ab72a72ea 100644 --- a/pkg/validatormanager/removal.go +++ b/pkg/validatormanager/removal.go @@ -203,7 +203,6 @@ func InitValidatorRemoval( if err != nil { return nil, ids.Empty, err } - ux.Logger.PrintToUser("Using validationID: %s for nodeID: %s", validationID, nodeID) aggregatorLogLevel, err := logging.ToLevel(aggregatorLogLevelStr) if err != nil { From f29392c7bc20d4a2b3a902b18bfe088430aed22c Mon Sep 17 00:00:00 2001 From: arturrez Date: Wed, 27 Nov 2024 09:45:17 -0800 Subject: [PATCH 08/31] increase staking reward --- tests/e2e/commands/etna.go | 2 +- tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/commands/etna.go b/tests/e2e/commands/etna.go index 66a99c9a3..594a860c0 100644 --- a/tests/e2e/commands/etna.go +++ b/tests/e2e/commands/etna.go @@ -41,7 +41,7 @@ func CreateEtnaSubnetEvmConfig( rewardBasisPoints := "" subnetManagementStr := PoAString if subnetManagementType == PoS { - rewardBasisPoints = "--reward-basis-points=10000000" + rewardBasisPoints = "--reward-basis-points=100000000" subnetManagementStr = PoSString } // Create config diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go index cfc60b2b3..40e6419ff 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go @@ -121,7 +121,7 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { }) ginkgo.It("Can wait for min staking period to pass", func() { - time.Sleep(120 * time.Second) + time.Sleep(180 * time.Second) }) ginkgo.It("Can remove non-bootstrap validator", func() { From 2be7ae26d5150167a3a4dbb2631d711662cfa0b7 Mon Sep 17 00:00:00 2001 From: arturrez Date: Wed, 27 Nov 2024 09:57:12 -0800 Subject: [PATCH 09/31] fix typo --- tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go index 40e6419ff..65e18a09b 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go @@ -110,7 +110,7 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { fmt.Println(output) }) - ginkgo.It("Can get status of thecluster", func() { + ginkgo.It("Can get status of the cluster", func() { output, err := commands.GetLocalClusterStatus(testLocalNodeName, subnetName) gomega.Expect(err).Should(gomega.BeNil()) fmt.Println(output) From ed76795d77610125011addeadb13877676641ba8 Mon Sep 17 00:00:00 2001 From: arturrez Date: Wed, 27 Nov 2024 10:54:50 -0800 Subject: [PATCH 10/31] add uptime deductible --- pkg/utils/staking.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/utils/staking.go b/pkg/utils/staking.go index f85660b0f..d6f96f5c7 100644 --- a/pkg/utils/staking.go +++ b/pkg/utils/staking.go @@ -98,6 +98,7 @@ func GetValidationTime(networkEndpoint string, nodeID ids.NodeID, subnetID ids.I // GetL1ValidatorUptimeSeconds returns the uptime of the L1 validator func GetL1ValidatorUptimeSeconds(rpcURL string, nodeID ids.NodeID) (uint64, error) { + const uptimeDeductible = uint64(10) // seconds to make sure all L1 validators would agree on uptime ctx, cancel := GetAPIContext() defer cancel() networkEndpoint, blockchainID, err := SplitRPCURI(rpcURL) @@ -110,7 +111,7 @@ func GetL1ValidatorUptimeSeconds(rpcURL string, nodeID ids.NodeID) (uint64, erro return 0, err } if len(validators) > 0 { - return validators[0].UptimeSeconds, nil + return validators[0].UptimeSeconds - uptimeDeductible, nil } return 0, errors.New("nodeID not found in validator set: " + nodeID.String()) From b3e70894fd2002305b4172cbe31557c213ca1e79 Mon Sep 17 00:00:00 2001 From: arturrez Date: Wed, 27 Nov 2024 11:37:42 -0800 Subject: [PATCH 11/31] add debug output to e2e --- tests/e2e/commands/etna.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/e2e/commands/etna.go b/tests/e2e/commands/etna.go index 594a860c0..736e2debf 100644 --- a/tests/e2e/commands/etna.go +++ b/tests/e2e/commands/etna.go @@ -41,7 +41,7 @@ func CreateEtnaSubnetEvmConfig( rewardBasisPoints := "" subnetManagementStr := PoAString if subnetManagementType == PoS { - rewardBasisPoints = "--reward-basis-points=100000000" + rewardBasisPoints = "--reward-basis-points=1000000000" subnetManagementStr = PoSString } // Create config @@ -64,6 +64,7 @@ func CreateEtnaSubnetEvmConfig( if rewardBasisPoints != "" { cmd.Args = append(cmd.Args, rewardBasisPoints) } + fmt.Println(cmd) output, err := cmd.CombinedOutput() fmt.Println(string(output)) if err != nil { From c0e30a3a950f0d764315d17d8b092850f15f263e Mon Sep 17 00:00:00 2001 From: arturrez Date: Wed, 27 Nov 2024 12:51:51 -0800 Subject: [PATCH 12/31] increse PoS e2e validator balance --- tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go index 65e18a09b..1b059b327 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go @@ -92,7 +92,7 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { subnetName, "http://127.0.0.1:9660", ewoqPChainAddress, - 1, + 100, ) gomega.Expect(err).Should(gomega.BeNil()) fmt.Println(output) @@ -104,7 +104,7 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { subnetName, "http://127.0.0.1:9662", ewoqPChainAddress, - 1, + 100, ) gomega.Expect(err).Should(gomega.BeNil()) fmt.Println(output) From c1d7415d8584bb7f0b189d3e4ff109953b41cc89 Mon Sep 17 00:00:00 2001 From: arturrez Date: Wed, 27 Nov 2024 14:06:41 -0800 Subject: [PATCH 13/31] proper e2e addvalidator config --- tests/e2e/commands/etna.go | 2 +- tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/e2e/commands/etna.go b/tests/e2e/commands/etna.go index 736e2debf..3adee4eb9 100644 --- a/tests/e2e/commands/etna.go +++ b/tests/e2e/commands/etna.go @@ -251,7 +251,7 @@ func AddEtnaSubnetValidatorToCluster( "--disable-owner", ewoqPChainAddress, "--stake-amount", - "2", + "200", "--delegation-fee", "100", "--staking-period", diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go index 1b059b327..65e18a09b 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go @@ -92,7 +92,7 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { subnetName, "http://127.0.0.1:9660", ewoqPChainAddress, - 100, + 1, ) gomega.Expect(err).Should(gomega.BeNil()) fmt.Println(output) @@ -104,7 +104,7 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { subnetName, "http://127.0.0.1:9662", ewoqPChainAddress, - 100, + 1, ) gomega.Expect(err).Should(gomega.BeNil()) fmt.Println(output) From 9448b5e1f9c72bd1f7765c1baa3cbbb222f8f098 Mon Sep 17 00:00:00 2001 From: arturrez Date: Wed, 27 Nov 2024 14:25:32 -0800 Subject: [PATCH 14/31] reduce stake amount --- tests/e2e/commands/etna.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/commands/etna.go b/tests/e2e/commands/etna.go index 3adee4eb9..62fe02d4b 100644 --- a/tests/e2e/commands/etna.go +++ b/tests/e2e/commands/etna.go @@ -251,7 +251,7 @@ func AddEtnaSubnetValidatorToCluster( "--disable-owner", ewoqPChainAddress, "--stake-amount", - "200", + "50", "--delegation-fee", "100", "--staking-period", From f9f2d37268d3fdb29f5c6ce66440fdb8bf80d362 Mon Sep 17 00:00:00 2001 From: arturrez Date: Wed, 27 Nov 2024 15:12:49 -0800 Subject: [PATCH 15/31] disable this check for now --- .../subnet/sov/addRemoveValidatorPoS/suite.go | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go index 65e18a09b..a809bae79 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go @@ -123,18 +123,18 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { ginkgo.It("Can wait for min staking period to pass", func() { time.Sleep(180 * time.Second) }) - - ginkgo.It("Can remove non-bootstrap validator", func() { - output, err := commands.RemoveEtnaSubnetValidatorFromCluster( - testLocalNodeName, - subnetName, - "http://127.0.0.1:9662", - keyName, - ) - gomega.Expect(err).Should(gomega.BeNil()) - fmt.Println(output) - }) - + /* + ginkgo.It("Can remove non-bootstrap validator", func() { + output, err := commands.RemoveEtnaSubnetValidatorFromCluster( + testLocalNodeName, + subnetName, + "http://127.0.0.1:9662", + keyName, + ) + gomega.Expect(err).Should(gomega.BeNil()) + fmt.Println(output) + }) + */ ginkgo.It("Can remove bootstrap validator", func() { output, err := commands.RemoveEtnaSubnetValidatorFromCluster( testLocalNodeName, From 326d3d9f2efda8fe7d2c6a50bd07e5eb28c544d8 Mon Sep 17 00:00:00 2001 From: arturrez Date: Wed, 27 Nov 2024 15:17:20 -0800 Subject: [PATCH 16/31] increase wait time for reward --- .../subnet/sov/addRemoveValidatorPoS/suite.go | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go index a809bae79..660e62301 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go @@ -121,20 +121,20 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { }) ginkgo.It("Can wait for min staking period to pass", func() { - time.Sleep(180 * time.Second) + time.Sleep(300 * time.Second) }) - /* - ginkgo.It("Can remove non-bootstrap validator", func() { - output, err := commands.RemoveEtnaSubnetValidatorFromCluster( - testLocalNodeName, - subnetName, - "http://127.0.0.1:9662", - keyName, - ) - gomega.Expect(err).Should(gomega.BeNil()) - fmt.Println(output) - }) - */ + + ginkgo.It("Can remove non-bootstrap validator", func() { + output, err := commands.RemoveEtnaSubnetValidatorFromCluster( + testLocalNodeName, + subnetName, + "http://127.0.0.1:9662", + keyName, + ) + gomega.Expect(err).Should(gomega.BeNil()) + fmt.Println(output) + }) + ginkgo.It("Can remove bootstrap validator", func() { output, err := commands.RemoveEtnaSubnetValidatorFromCluster( testLocalNodeName, From aa419d1b14f8875a2d5445759b504075f9a42ddf Mon Sep 17 00:00:00 2001 From: arturrez Date: Wed, 27 Nov 2024 15:32:34 -0800 Subject: [PATCH 17/31] adjust params --- tests/e2e/commands/etna.go | 2 +- tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/commands/etna.go b/tests/e2e/commands/etna.go index 62fe02d4b..86f850884 100644 --- a/tests/e2e/commands/etna.go +++ b/tests/e2e/commands/etna.go @@ -251,7 +251,7 @@ func AddEtnaSubnetValidatorToCluster( "--disable-owner", ewoqPChainAddress, "--stake-amount", - "50", + "100", "--delegation-fee", "100", "--staking-period", diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go index 660e62301..81513d7e3 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go @@ -121,7 +121,7 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { }) ginkgo.It("Can wait for min staking period to pass", func() { - time.Sleep(300 * time.Second) + time.Sleep(600 * time.Second) }) ginkgo.It("Can remove non-bootstrap validator", func() { From 03e87c23b2d0ccfa8c65b71078ff040ca17cd2e9 Mon Sep 17 00:00:00 2001 From: arturrez Date: Thu, 28 Nov 2024 12:34:31 -0800 Subject: [PATCH 18/31] add manual uptime for e2e --- tests/e2e/commands/etna.go | 3 +++ .../subnet/sov/addRemoveValidatorPoS/suite.go | 20 +++++-------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/tests/e2e/commands/etna.go b/tests/e2e/commands/etna.go index 86f850884..5b0067da0 100644 --- a/tests/e2e/commands/etna.go +++ b/tests/e2e/commands/etna.go @@ -274,6 +274,7 @@ func RemoveEtnaSubnetValidatorFromCluster( subnetName string, nodeEndpoint string, keyName string, + uptimeSec uint64, ) (string, error) { cmd := exec.Command( CLIBinary, @@ -289,6 +290,8 @@ func RemoveEtnaSubnetValidatorFromCluster( keyName, "--key", keyName, + "--uptime", + strconv.Itoa(int(uptimeSec)), "--"+constants.SkipUpdateFlag, ) output, err := cmd.CombinedOutput() diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go index 81513d7e3..d45b9ee12 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go @@ -98,18 +98,6 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { fmt.Println(output) }) - ginkgo.It("Can add second validator", func() { - output, err := commands.AddEtnaSubnetValidatorToCluster( - testLocalNodeName, - subnetName, - "http://127.0.0.1:9662", - ewoqPChainAddress, - 1, - ) - gomega.Expect(err).Should(gomega.BeNil()) - fmt.Println(output) - }) - ginkgo.It("Can get status of the cluster", func() { output, err := commands.GetLocalClusterStatus(testLocalNodeName, subnetName) gomega.Expect(err).Should(gomega.BeNil()) @@ -120,16 +108,17 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { gomega.Expect(output).To(gomega.MatchRegexp(`http://127\.0\.0\.1:9654.*Validating`), "expect to have L1 validating") }) - ginkgo.It("Can wait for min staking period to pass", func() { - time.Sleep(600 * time.Second) + ginkgo.It("Can wait for 3 mins for the staking period to pass", func() { + time.Sleep(180 * time.Second) }) ginkgo.It("Can remove non-bootstrap validator", func() { output, err := commands.RemoveEtnaSubnetValidatorFromCluster( testLocalNodeName, subnetName, - "http://127.0.0.1:9662", + "http://127.0.0.1:9660", keyName, + 60, ) gomega.Expect(err).Should(gomega.BeNil()) fmt.Println(output) @@ -141,6 +130,7 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { subnetName, "http://127.0.0.1:9654", keyName, + 0, ) gomega.Expect(err).Should(gomega.BeNil()) fmt.Println(output) From 74ccf05a904d450f849c5da0d6e67aba504d9a3c Mon Sep 17 00:00:00 2001 From: arturrez Date: Thu, 28 Nov 2024 12:37:30 -0800 Subject: [PATCH 19/31] fix --- tests/e2e/testcases/subnet/sov/addRemoveValidatorPoA/suite.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoA/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoA/suite.go index 3be59448a..ffd117d7c 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoA/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoA/suite.go @@ -124,6 +124,7 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoA]", func() { subnetName, "http://127.0.0.1:9654", keyName, + 0, ) gomega.Expect(err).Should(gomega.BeNil()) fmt.Println(output) @@ -135,6 +136,7 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoA]", func() { subnetName, "http://127.0.0.1:9660", keyName, + 0, ) gomega.Expect(err).Should(gomega.BeNil()) fmt.Println(output) From 4ea062592f092c044fe80b0a1d336d6f5b05eab2 Mon Sep 17 00:00:00 2001 From: arturrez Date: Thu, 28 Nov 2024 13:28:53 -0800 Subject: [PATCH 20/31] 5 mins before status --- .../testcases/subnet/sov/addRemoveValidatorPoS/suite.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go index d45b9ee12..293c94e63 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go @@ -98,6 +98,10 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { fmt.Println(output) }) + ginkgo.It("Can wait for 3 mins for the staking period to pass", func() { + time.Sleep(300 * time.Second) + }) + ginkgo.It("Can get status of the cluster", func() { output, err := commands.GetLocalClusterStatus(testLocalNodeName, subnetName) gomega.Expect(err).Should(gomega.BeNil()) @@ -108,10 +112,6 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { gomega.Expect(output).To(gomega.MatchRegexp(`http://127\.0\.0\.1:9654.*Validating`), "expect to have L1 validating") }) - ginkgo.It("Can wait for 3 mins for the staking period to pass", func() { - time.Sleep(180 * time.Second) - }) - ginkgo.It("Can remove non-bootstrap validator", func() { output, err := commands.RemoveEtnaSubnetValidatorFromCluster( testLocalNodeName, From b54875567fcef5122a949c5ab4be7970341c4d9c Mon Sep 17 00:00:00 2001 From: arturrez Date: Thu, 28 Nov 2024 13:42:03 -0800 Subject: [PATCH 21/31] rm sleep and e2e for check rm validator with uptime --- .../subnet/sov/addRemoveValidatorPoS/suite.go | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go index 293c94e63..bd0333dba 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go @@ -6,7 +6,6 @@ package subnet import ( "fmt" "regexp" - "time" "github.com/ava-labs/avalanche-cli/tests/e2e/commands" ginkgo "github.com/onsi/ginkgo/v2" @@ -98,10 +97,6 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { fmt.Println(output) }) - ginkgo.It("Can wait for 3 mins for the staking period to pass", func() { - time.Sleep(300 * time.Second) - }) - ginkgo.It("Can get status of the cluster", func() { output, err := commands.GetLocalClusterStatus(testLocalNodeName, subnetName) gomega.Expect(err).Should(gomega.BeNil()) @@ -112,18 +107,6 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { gomega.Expect(output).To(gomega.MatchRegexp(`http://127\.0\.0\.1:9654.*Validating`), "expect to have L1 validating") }) - ginkgo.It("Can remove non-bootstrap validator", func() { - output, err := commands.RemoveEtnaSubnetValidatorFromCluster( - testLocalNodeName, - subnetName, - "http://127.0.0.1:9660", - keyName, - 60, - ) - gomega.Expect(err).Should(gomega.BeNil()) - fmt.Println(output) - }) - ginkgo.It("Can remove bootstrap validator", func() { output, err := commands.RemoveEtnaSubnetValidatorFromCluster( testLocalNodeName, From 71c894d359106ef48e79afa0d6bc4815728a70ec Mon Sep 17 00:00:00 2001 From: arturrez Date: Mon, 2 Dec 2024 13:10:02 -0800 Subject: [PATCH 22/31] add force flag to remove validators. allow validator removal with 0 reward --- cmd/blockchaincmd/change_weight.go | 3 +- cmd/blockchaincmd/remove_validator.go | 75 +++++++++++++++---- pkg/validatormanager/removal.go | 1 + tests/e2e/commands/etna.go | 1 + .../subnet/sov/addRemoveValidatorPoS/suite.go | 12 +++ 5 files changed, 76 insertions(+), 16 deletions(-) diff --git a/cmd/blockchaincmd/change_weight.go b/cmd/blockchaincmd/change_weight.go index 4f349569a..dde8a66af 100644 --- a/cmd/blockchaincmd/change_weight.go +++ b/cmd/blockchaincmd/change_weight.go @@ -152,7 +152,8 @@ func setWeight(_ *cobra.Command, args []string) error { network, blockchainName, nodeID, - 0, // automatic uptime + 0, // automatic uptime + isBootstrapValidatorForNetwork(nodeID, sc.Networks[network.Name()]), false, // don't force ) if err != nil { diff --git a/cmd/blockchaincmd/remove_validator.go b/cmd/blockchaincmd/remove_validator.go index 7bd84684c..9e6d114ae 100644 --- a/cmd/blockchaincmd/remove_validator.go +++ b/cmd/blockchaincmd/remove_validator.go @@ -22,8 +22,10 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" "github.com/ava-labs/avalanche-cli/pkg/validatormanager" + validatormanagerSDK "github.com/ava-labs/avalanche-cli/sdk/validatormanager" "github.com/ava-labs/avalanchego/genesis" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/secp256k1fx" "github.com/spf13/cobra" ) @@ -36,7 +38,10 @@ var removeValidatorSupportedNetworkOptions = []networkoptions.NetworkOption{ networkoptions.EtnaDevnet, } -var uptimeSec uint64 +var ( + uptimeSec uint64 + force bool +) // avalanche blockchain removeValidator func newRemoveValidatorCmd() *cobra.Command { @@ -64,6 +69,7 @@ these prompts by providing the values with flags.`, cmd.Flags().StringVar(&rpcURL, "rpc", "", "connect to validator manager at the given rpc endpoint") cmd.Flags().StringVar(&aggregatorLogLevel, "aggregator-log-level", "Off", "log level to use with signature aggregator") cmd.Flags().Uint64Var(&uptimeSec, "uptime", 0, "validator's uptime in seconds. If not provided, it will be automatically calculated") + cmd.Flags().BoolVar(&force, "force", false, "force validator removal even if it's not getting rewarded") return cmd } @@ -178,15 +184,15 @@ func removeValidator(_ *cobra.Command, args []string) error { } return removeValidatorNonSOV(deployer, network, subnetID, kc, blockchainName, nodeID) } - // check if node is a bootstrap validator to force it to be removed - filteredBootstrapValidators := utils.Filter(scNetwork.BootstrapValidators, func(b models.SubnetValidator) bool { - if id, err := ids.NodeIDFromString(b.NodeID); err == nil && id == nodeID { - return true - } - return false - }) - force := len(filteredBootstrapValidators) > 0 - if err := removeValidatorSOV(deployer, network, blockchainName, nodeID, uptimeSec, force); err != nil { + if err := removeValidatorSOV( + deployer, + network, + blockchainName, + nodeID, + uptimeSec, + isBootstrapValidatorForNetwork(nodeID, scNetwork), + force, + ); err != nil { return err } // remove the validator from the list of bootstrap validators @@ -205,12 +211,23 @@ func removeValidator(_ *cobra.Command, args []string) error { return nil } +func isBootstrapValidatorForNetwork(nodeID ids.NodeID, scNetwork models.NetworkData) bool { + filteredBootstrapValidators := utils.Filter(scNetwork.BootstrapValidators, func(b models.SubnetValidator) bool { + if id, err := ids.NodeIDFromString(b.NodeID); err == nil && id == nodeID { + return true + } + return false + }) + return len(filteredBootstrapValidators) > 0 +} + func removeValidatorSOV( deployer *subnet.PublicDeployer, network models.Network, blockchainName string, nodeID ids.NodeID, uptimeSec uint64, + isBootstrapValidator bool, force bool, ) error { chainSpec := contract.ChainSpec{ @@ -257,7 +274,12 @@ func removeValidatorSOV( ux.Logger.PrintToUser(logging.Yellow.Wrap("Forcing removal of %s as it is a PoS bootstrap validator"), nodeID) } - signedMessage, validationID, err := validatormanager.InitValidatorRemoval( + var ( + signedMessage *warp.Message + validationID ids.ID + ) + // try to remove the validator. If err is "delegator ineligible for rewards" confirm with user and force remove + signedMessage, validationID, err = validatormanager.InitValidatorRemoval( app, network, rpcURL, @@ -268,13 +290,37 @@ func removeValidatorSOV( aggregatorLogLevel, sc.PoS(), uptimeSec, - force, + isBootstrapValidator || force, ) - if err != nil { + if err != nil && err != validatormanagerSDK.ErrValidatorIneligibleForRewards { return err + } else if err == validatormanagerSDK.ErrValidatorIneligibleForRewards { + ux.Logger.PrintToUser("Validator %s is not eligible for rewards", nodeID) + force, err = app.Prompt.CaptureNoYes("Are you sure you want to still remove the validator?") + if err != nil { + return err + } + if !force { + return fmt.Errorf("validator %s is not eligible for rewards. Use --force flag to force removal", nodeID) + } + signedMessage, validationID, err = validatormanager.InitValidatorRemoval( + app, + network, + rpcURL, + chainSpec, + ownerPrivateKey, + nodeID, + extraAggregatorPeers, + aggregatorLogLevel, + sc.PoS(), + uptimeSec, + true, // force + ) + if err != nil { + return err + } } ux.Logger.PrintToUser("ValidationID: %s", validationID) - txID, _, err := deployer.SetL1ValidatorWeight(signedMessage) if err != nil { return err @@ -293,7 +339,6 @@ func removeValidatorSOV( ); err != nil { return err } - ux.Logger.GreenCheckmarkToUser("Validator successfully removed from the Subnet") return nil diff --git a/pkg/validatormanager/removal.go b/pkg/validatormanager/removal.go index c610bc46e..738e8d6cc 100644 --- a/pkg/validatormanager/removal.go +++ b/pkg/validatormanager/removal.go @@ -109,6 +109,7 @@ func GetUptimeProofMessage( aggregatorLogLevel, subnetID, aggregatorQuorumPercentage, + true, // allow private peers aggregatorExtraPeerEndpoints, ) if err != nil { diff --git a/tests/e2e/commands/etna.go b/tests/e2e/commands/etna.go index 5b0067da0..82558fc5a 100644 --- a/tests/e2e/commands/etna.go +++ b/tests/e2e/commands/etna.go @@ -292,6 +292,7 @@ func RemoveEtnaSubnetValidatorFromCluster( keyName, "--uptime", strconv.Itoa(int(uptimeSec)), + "--force", "--"+constants.SkipUpdateFlag, ) output, err := cmd.CombinedOutput() diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go index bd0333dba..052bee2b9 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go @@ -107,6 +107,18 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { gomega.Expect(output).To(gomega.MatchRegexp(`http://127\.0\.0\.1:9654.*Validating`), "expect to have L1 validating") }) + ginkgo.It("Can remove non-bootstrap validator", func() { + output, err := commands.RemoveEtnaSubnetValidatorFromCluster( + testLocalNodeName, + subnetName, + "http://127.0.0.1:9660", + keyName, + 0, + ) + gomega.Expect(err).Should(gomega.BeNil()) + fmt.Println(output) + }) + ginkgo.It("Can remove bootstrap validator", func() { output, err := commands.RemoveEtnaSubnetValidatorFromCluster( testLocalNodeName, From 89654f9b6968367456d5fa378dcf9ee1765af73e Mon Sep 17 00:00:00 2001 From: arturrez Date: Mon, 2 Dec 2024 13:21:07 -0800 Subject: [PATCH 23/31] add check for failed removal and also sleep in e2e waiting for min duration to pass --- .../testcases/subnet/sov/addRemoveValidatorPoS/suite.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go index 052bee2b9..23ba77f64 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go @@ -6,6 +6,7 @@ package subnet import ( "fmt" "regexp" + "time" "github.com/ava-labs/avalanche-cli/tests/e2e/commands" ginkgo "github.com/onsi/ginkgo/v2" @@ -107,7 +108,7 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { gomega.Expect(output).To(gomega.MatchRegexp(`http://127\.0\.0\.1:9654.*Validating`), "expect to have L1 validating") }) - ginkgo.It("Can remove non-bootstrap validator", func() { + ginkgo.It("Can fail to remove non-bootstrap validator before min stake duration", func() { output, err := commands.RemoveEtnaSubnetValidatorFromCluster( testLocalNodeName, subnetName, @@ -115,10 +116,14 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { keyName, 0, ) - gomega.Expect(err).Should(gomega.BeNil()) + gomega.Expect(err.Error()).Should(gomega.ContainSubstring("min stake duration not passed")) fmt.Println(output) }) + ginkgo.It("Can sleep for min stake duration", func() { + time.Sleep(3 * time.Minute) + }) + ginkgo.It("Can remove bootstrap validator", func() { output, err := commands.RemoveEtnaSubnetValidatorFromCluster( testLocalNodeName, From 4082bdca3e7735ce90712fd270734e1fd493b1ca Mon Sep 17 00:00:00 2001 From: arturrez Date: Mon, 2 Dec 2024 13:34:20 -0800 Subject: [PATCH 24/31] rm e2e check - no cli value --- .../subnet/sov/addRemoveValidatorPoS/suite.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go index 23ba77f64..06a37940d 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go @@ -108,18 +108,6 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { gomega.Expect(output).To(gomega.MatchRegexp(`http://127\.0\.0\.1:9654.*Validating`), "expect to have L1 validating") }) - ginkgo.It("Can fail to remove non-bootstrap validator before min stake duration", func() { - output, err := commands.RemoveEtnaSubnetValidatorFromCluster( - testLocalNodeName, - subnetName, - "http://127.0.0.1:9660", - keyName, - 0, - ) - gomega.Expect(err.Error()).Should(gomega.ContainSubstring("min stake duration not passed")) - fmt.Println(output) - }) - ginkgo.It("Can sleep for min stake duration", func() { time.Sleep(3 * time.Minute) }) From 5b8c0ba901f8f21772e0bc265d4287276a92eb28 Mon Sep 17 00:00:00 2001 From: arturrez Date: Mon, 2 Dec 2024 13:36:11 -0800 Subject: [PATCH 25/31] minor refactor --- cmd/blockchaincmd/remove_validator.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd/blockchaincmd/remove_validator.go b/cmd/blockchaincmd/remove_validator.go index 9e6d114ae..4f2b8ea76 100644 --- a/cmd/blockchaincmd/remove_validator.go +++ b/cmd/blockchaincmd/remove_validator.go @@ -292,9 +292,7 @@ func removeValidatorSOV( uptimeSec, isBootstrapValidator || force, ) - if err != nil && err != validatormanagerSDK.ErrValidatorIneligibleForRewards { - return err - } else if err == validatormanagerSDK.ErrValidatorIneligibleForRewards { + if err != nil && err == validatormanagerSDK.ErrValidatorIneligibleForRewards { ux.Logger.PrintToUser("Validator %s is not eligible for rewards", nodeID) force, err = app.Prompt.CaptureNoYes("Are you sure you want to still remove the validator?") if err != nil { @@ -319,7 +317,10 @@ func removeValidatorSOV( if err != nil { return err } + } else if err != nil { + return err } + ux.Logger.PrintToUser("ValidationID: %s", validationID) txID, _, err := deployer.SetL1ValidatorWeight(signedMessage) if err != nil { From 01f1790bc335b5f01b55a84ae9fb72177ee2ff4a Mon Sep 17 00:00:00 2001 From: arturrez Date: Wed, 4 Dec 2024 15:08:55 -0800 Subject: [PATCH 26/31] put func getBlockchainTimestamp back after bad merge --- cmd/blockchaincmd/add_validator.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cmd/blockchaincmd/add_validator.go b/cmd/blockchaincmd/add_validator.go index 3d4339bdd..aaf1006e5 100644 --- a/cmd/blockchaincmd/add_validator.go +++ b/cmd/blockchaincmd/add_validator.go @@ -30,6 +30,7 @@ import ( avagoconstants "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/formatting/address" "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ava-labs/avalanchego/vms/platformvm" warpMessage "github.com/ava-labs/avalanchego/vms/platformvm/warp/message" "github.com/spf13/cobra" ) @@ -591,6 +592,13 @@ func PromptDuration(start time.Time, network models.Network) (time.Duration, err } } +func getBlockchainTimestamp(network models.Network) (time.Time, error) { + ctx, cancel := utils.GetAPIContext() + defer cancel() + platformCli := platformvm.NewClient(network.Endpoint) + return platformCli.GetTimestamp(ctx) +} + func getTimeParameters(network models.Network, nodeID ids.NodeID, isValidator bool) (time.Time, time.Duration, error) { defaultStakingStartLeadTime := constants.StakingStartLeadTime if network.Kind == models.Devnet { From b8c35381160dcbcd088d498fa167b1f0d61c3d66 Mon Sep 17 00:00:00 2001 From: arturrez Date: Fri, 6 Dec 2024 11:48:54 -0800 Subject: [PATCH 27/31] parameter stake amount for e2e --- tests/e2e/commands/etna.go | 3 ++- tests/e2e/testcases/subnet/sov/addRemoveValidatorPoA/suite.go | 2 ++ tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go | 2 ++ tests/e2e/testcases/subnet/sov/addValidatorLocal/suite.go | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/e2e/commands/etna.go b/tests/e2e/commands/etna.go index 0ca88aac3..31dbb4dc7 100644 --- a/tests/e2e/commands/etna.go +++ b/tests/e2e/commands/etna.go @@ -233,6 +233,7 @@ func AddEtnaSubnetValidatorToCluster( nodeEndpoint string, ewoqPChainAddress string, balance int, + stakeAmount int, createLocalValidator bool, ) (string, error) { cmd := exec.Command( @@ -248,7 +249,7 @@ func AddEtnaSubnetValidatorToCluster( "--disable-owner", ewoqPChainAddress, "--stake-amount", - "100", + strconv.Itoa(stakeAmount), "--delegation-fee", "100", "--staking-period", diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoA/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoA/suite.go index fc64eb277..c1a75e560 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoA/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoA/suite.go @@ -91,6 +91,7 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoA]", func() { "http://127.0.0.1:9660", ewoqPChainAddress, 1, + 100, false, // use existing avago running ) gomega.Expect(err).Should(gomega.BeNil()) @@ -104,6 +105,7 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoA]", func() { "http://127.0.0.1:9662", ewoqPChainAddress, 1, + 100, false, // use existing avago running ) gomega.Expect(err).Should(gomega.BeNil()) diff --git a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go index 3fbf88c70..d56409bc7 100644 --- a/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go +++ b/tests/e2e/testcases/subnet/sov/addRemoveValidatorPoS/suite.go @@ -93,6 +93,7 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { "http://127.0.0.1:9660", ewoqPChainAddress, 1, + 100, false, // use existing ) gomega.Expect(err).Should(gomega.BeNil()) @@ -106,6 +107,7 @@ var _ = ginkgo.Describe("[Etna AddRemove Validator SOV PoS]", func() { "http://127.0.0.1:9662", ewoqPChainAddress, 1, + 100, false, // use existing ) gomega.Expect(err).Should(gomega.BeNil()) diff --git a/tests/e2e/testcases/subnet/sov/addValidatorLocal/suite.go b/tests/e2e/testcases/subnet/sov/addValidatorLocal/suite.go index 6ab1ee2c9..1d25c009b 100644 --- a/tests/e2e/testcases/subnet/sov/addValidatorLocal/suite.go +++ b/tests/e2e/testcases/subnet/sov/addValidatorLocal/suite.go @@ -44,6 +44,7 @@ var _ = ginkgo.Describe("[Etna Add Validator SOV Local]", func() { "", ewoqPChainAddress, 1, + 1, true, ) gomega.Expect(err).Should(gomega.BeNil()) From 2a543698f9c07a9d518014b9c2cab177a2f7e7da Mon Sep 17 00:00:00 2001 From: Raymond Sukanto Date: Mon, 9 Dec 2024 19:48:26 -0500 Subject: [PATCH 28/31] fix lint --- cmd/blockchaincmd/remove_validator.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/blockchaincmd/remove_validator.go b/cmd/blockchaincmd/remove_validator.go index 01488659a..faa4a9e99 100644 --- a/cmd/blockchaincmd/remove_validator.go +++ b/cmd/blockchaincmd/remove_validator.go @@ -294,9 +294,9 @@ func removeValidatorSOV( uptimeSec, isBootstrapValidator || force, ) - if err != nil && err == validatormanagerSDK.ErrValidatorIneligibleForRewards { + if err != nil && errors.Is(err, validatormanagerSDK.ErrValidatorIneligibleForRewards) { ux.Logger.PrintToUser("Validator %s is not eligible for rewards", nodeID) - force, err = app.Prompt.CaptureNoYes("Are you sure you want to still remove the validator?") + force, err = app.Prompt.CaptureNoYes("Do you want to continue with validator removal?") if err != nil { return err } @@ -311,6 +311,7 @@ func removeValidatorSOV( ownerPrivateKey, nodeID, extraAggregatorPeers, + aggregatorAllowPrivatePeers, aggregatorLogLevel, sc.PoS(), uptimeSec, From ee6279f7ac5fbcd17a82164c8c219e7e9794a49c Mon Sep 17 00:00:00 2001 From: arturrez Date: Wed, 11 Dec 2024 11:56:10 -0800 Subject: [PATCH 29/31] address feedback --- cmd/blockchaincmd/add_validator.go | 2 +- cmd/blockchaincmd/remove_validator.go | 2 +- pkg/constants/constants.go | 2 ++ pkg/utils/net.go | 4 +--- pkg/utils/net_test.go | 20 +++++++------------- pkg/utils/staking.go | 11 +++++------ 6 files changed, 17 insertions(+), 24 deletions(-) diff --git a/cmd/blockchaincmd/add_validator.go b/cmd/blockchaincmd/add_validator.go index db4e3ae3c..8db3af4ad 100644 --- a/cmd/blockchaincmd/add_validator.go +++ b/cmd/blockchaincmd/add_validator.go @@ -766,7 +766,7 @@ func getTimeParameters(network models.Network, nodeID ids.NodeID, isValidator bo var selectedDuration time.Duration if useDefaultDuration { // avoid setting both globals useDefaultDuration and duration - selectedDuration, err = utils.GetValidationTime(network.Endpoint, nodeID, avagoconstants.PrimaryNetworkID, start) + selectedDuration, err = utils.GetRemainingValidationTime(network.Endpoint, nodeID, avagoconstants.PrimaryNetworkID, start) if err != nil { return time.Time{}, 0, err } diff --git a/cmd/blockchaincmd/remove_validator.go b/cmd/blockchaincmd/remove_validator.go index e2c0ea30d..b52130fa6 100644 --- a/cmd/blockchaincmd/remove_validator.go +++ b/cmd/blockchaincmd/remove_validator.go @@ -291,7 +291,7 @@ func removeValidatorSOV( isBootstrapValidator || force, ) if err != nil && errors.Is(err, validatormanagerSDK.ErrValidatorIneligibleForRewards) { - ux.Logger.PrintToUser("Validator %s is not eligible for rewards", nodeID) + ux.Logger.PrintToUser("Calculated rewards is zero. Validator %s is not eligible for rewards", nodeID) force, err = app.Prompt.CaptureNoYes("Do you want to continue with validator removal?") if err != nil { return err diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 34fe2a6bb..523c95c60 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -332,4 +332,6 @@ const ( MainnetCChainICMRegistryAddress = "0x7C43605E14F391720e1b37E49C78C4b03A488d98" FujiCChainICMRegistryAddress = "0xF86Cb19Ad8405AEFa7d09C778215D2Cb6eBfB228" EtnaDevnetCChainICMRegistryAddress = "0xEe40DFF876204A99eCCB783FDc01eE0a2678Ae93" + + ValidatorUptimeDeductible = uint64(10) // seconds to make sure all L1 validators would agree on uptime ) diff --git a/pkg/utils/net.go b/pkg/utils/net.go index 6a480e9d1..99d466898 100644 --- a/pkg/utils/net.go +++ b/pkg/utils/net.go @@ -71,9 +71,7 @@ func IsValidIPPort(ipPortPair string) bool { // SplitRPCURI splits the RPC URI into `endpoint` and `chain`. // Reverse operation of `fmt.Sprintf("%s/ext/bc/%s", endpoint, chain)`. // returns the `uri` and `chain` as strings, or an error if the request URI is invalid. -// SplitRPCURI splits the RPC URL into `endpoint` and `chain`. -// It matches the pattern `http:///ext/bc//rpc` using a regex. -func SplitRPCURI(requestURI string) (string, string, error) { +func SplitAvalanchegoRPCURI(requestURI string) (string, string, error) { // Define the regex pattern pattern := `^(https?://[^/]+)/ext/bc/([^/]+)/rpc$` regex := regexp.MustCompile(pattern) diff --git a/pkg/utils/net_test.go b/pkg/utils/net_test.go index 0863ca22d..fff2fcef6 100644 --- a/pkg/utils/net_test.go +++ b/pkg/utils/net_test.go @@ -4,6 +4,8 @@ package utils import ( "testing" + + "github.com/stretchr/testify/require" ) func TestIsValidIPPort(t *testing.T) { @@ -77,22 +79,14 @@ func TestSplitRPCURI(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - endpoint, chain, err := SplitRPCURI(tt.requestURI) + endpoint, chain, err := SplitAvalanchegoRPCURI(tt.requestURI) if tt.expectError { - if err == nil { - t.Errorf("expected an error but got nil") - } + require.Error(t, err, "expected an error but got nil") } else { - if err != nil { - t.Errorf("did not expect an error but got: %v", err) - } - if endpoint != tt.expectedEndpoint { - t.Errorf("expected Endpoint: %s, got: %s", tt.expectedEndpoint, endpoint) - } - if chain != tt.expectedChain { - t.Errorf("expected Chain: %s, got: %s", tt.expectedChain, chain) - } + require.NoError(t, err, "did not expect an error but got one") + require.Equal(t, tt.expectedEndpoint, endpoint, "unexpected Endpoint") + require.Equal(t, tt.expectedChain, chain, "unexpected Chain") } }) } diff --git a/pkg/utils/staking.go b/pkg/utils/staking.go index d6f96f5c7..fa2df1f19 100644 --- a/pkg/utils/staking.go +++ b/pkg/utils/staking.go @@ -17,7 +17,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/signer" - subnetEvmPlugin "github.com/ava-labs/subnet-evm/plugin/evm" + "github.com/ava-labs/subnet-evm/plugin/evm" ) func NewBlsSecretKeyBytes() ([]byte, error) { @@ -79,7 +79,7 @@ func GetNodeParams(nodeDir string) ( return nodeID, blsPub, blsPoP, nil } -func GetValidationTime(networkEndpoint string, nodeID ids.NodeID, subnetID ids.ID, startTime time.Time) (time.Duration, error) { +func GetRemainingValidationTime(networkEndpoint string, nodeID ids.NodeID, subnetID ids.ID, startTime time.Time) (time.Duration, error) { ctx, cancel := GetAPIContext() defer cancel() platformCli := platformvm.NewClient(networkEndpoint) @@ -98,20 +98,19 @@ func GetValidationTime(networkEndpoint string, nodeID ids.NodeID, subnetID ids.I // GetL1ValidatorUptimeSeconds returns the uptime of the L1 validator func GetL1ValidatorUptimeSeconds(rpcURL string, nodeID ids.NodeID) (uint64, error) { - const uptimeDeductible = uint64(10) // seconds to make sure all L1 validators would agree on uptime ctx, cancel := GetAPIContext() defer cancel() - networkEndpoint, blockchainID, err := SplitRPCURI(rpcURL) + networkEndpoint, blockchainID, err := SplitAvalanchegoRPCURI(rpcURL) if err != nil { return 0, err } - evmCli := subnetEvmPlugin.NewClient(networkEndpoint, blockchainID) + evmCli := evm.NewClient(networkEndpoint, blockchainID) validators, err := evmCli.GetCurrentValidators(ctx, []ids.NodeID{nodeID}) if err != nil { return 0, err } if len(validators) > 0 { - return validators[0].UptimeSeconds - uptimeDeductible, nil + return validators[0].UptimeSeconds - constants.ValidatorUptimeDeductible, nil } return 0, errors.New("nodeID not found in validator set: " + nodeID.String()) From 2fc67ff9568541be69f50eb840bc8621fff5493b Mon Sep 17 00:00:00 2001 From: arturrez Date: Wed, 11 Dec 2024 12:01:42 -0800 Subject: [PATCH 30/31] rm debug --- pkg/validatormanager/validatormanager.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/validatormanager/validatormanager.go b/pkg/validatormanager/validatormanager.go index 0318a0cd4..fa9e1e0b5 100644 --- a/pkg/validatormanager/validatormanager.go +++ b/pkg/validatormanager/validatormanager.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/ava-labs/avalanche-cli/pkg/models" - "github.com/ava-labs/avalanche-cli/pkg/ux" blockchainSDK "github.com/ava-labs/avalanche-cli/sdk/blockchain" validatorManagerSDK "github.com/ava-labs/avalanche-cli/sdk/validatormanager" "github.com/ava-labs/avalanchego/api/info" @@ -91,7 +90,6 @@ func AddRewardCalculatorToAllocations( allocs core.GenesisAlloc, rewardBasisPoints uint64, ) { - ux.Logger.PrintToUser("Adding reward calculator contract to allocations %d", rewardBasisPoints) deployedRewardCalculatorBytes := common.FromHex(strings.TrimSpace(string(deployedRewardCalculatorBytecode))) allocs[common.HexToAddress(validatorManagerSDK.RewardCalculatorAddress)] = core.GenesisAccount{ Balance: big.NewInt(0), From d1e496d4c874a48ad15183bc88115ea7bb8a94be Mon Sep 17 00:00:00 2001 From: arturrez Date: Wed, 11 Dec 2024 15:32:09 -0800 Subject: [PATCH 31/31] revert ApplyDefaultDenomination here --- cmd/blockchaincmd/deploy.go | 4 ++-- cmd/contractcmd/init_validator_manager.go | 5 ++-- pkg/utils/decimals.go | 28 ----------------------- 3 files changed, 4 insertions(+), 33 deletions(-) delete mode 100644 pkg/utils/decimals.go diff --git a/cmd/blockchaincmd/deploy.go b/cmd/blockchaincmd/deploy.go index a90460e0b..163d0958e 100644 --- a/cmd/blockchaincmd/deploy.go +++ b/cmd/blockchaincmd/deploy.go @@ -1044,8 +1044,8 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { aggregatorAllowPrivatePeers, logLvl, validatorManagerSDK.PoSParams{ - MinimumStakeAmount: utils.ApplyDefaultDenomination(poSMinimumStakeAmount), - MaximumStakeAmount: utils.ApplyDefaultDenomination(poSMaximumStakeAmount), + MinimumStakeAmount: big.NewInt(int64(poSMinimumStakeAmount)), + MaximumStakeAmount: big.NewInt(int64(poSMaximumStakeAmount)), MinimumStakeDuration: poSMinimumStakeDuration, MinimumDelegationFee: poSMinimumDelegationFee, MaximumStakeMultiplier: poSMaximumStakeMultiplier, diff --git a/cmd/contractcmd/init_validator_manager.go b/cmd/contractcmd/init_validator_manager.go index 05afcb0d2..d064f8fb7 100644 --- a/cmd/contractcmd/init_validator_manager.go +++ b/cmd/contractcmd/init_validator_manager.go @@ -12,7 +12,6 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/models" "github.com/ava-labs/avalanche-cli/pkg/networkoptions" "github.com/ava-labs/avalanche-cli/pkg/prompts" - "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" "github.com/ava-labs/avalanche-cli/pkg/validatormanager" blockchainSDK "github.com/ava-labs/avalanche-cli/sdk/blockchain" @@ -206,8 +205,8 @@ func initValidatorManager(_ *cobra.Command, args []string) error { validatorManagerFlags.aggregatorAllowPrivatePeers, validatorManagerFlags.aggregatorLogLevel, validatorManagerSDK.PoSParams{ - MinimumStakeAmount: utils.ApplyDefaultDenomination(initPOSManagerFlags.minimumStakeAmount), - MaximumStakeAmount: utils.ApplyDefaultDenomination(initPOSManagerFlags.maximumStakeAmount), + MinimumStakeAmount: big.NewInt(int64(initPOSManagerFlags.minimumStakeAmount)), + MaximumStakeAmount: big.NewInt(int64(initPOSManagerFlags.maximumStakeAmount)), MinimumStakeDuration: initPOSManagerFlags.minimumStakeDuration, MinimumDelegationFee: initPOSManagerFlags.minimumDelegationFee, MaximumStakeMultiplier: initPOSManagerFlags.maximumStakeMultiplier, diff --git a/pkg/utils/decimals.go b/pkg/utils/decimals.go deleted file mode 100644 index 28e4f2bef..000000000 --- a/pkg/utils/decimals.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (C) 2023, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. -package utils - -import ( - "math/big" -) - -const defaultDenomination = 18 - -// Convert an integed amount of the given denomination to base units -// (i.e. An amount of 54 with a decimals value of 3 results in 54000) -func ApplyDenomination(amount uint64, decimals uint8) *big.Int { - multiplier := new(big.Int).Exp( - big.NewInt(10), - big.NewInt(int64(decimals)), - nil, - ) - return new(big.Int).Mul( - big.NewInt(int64(amount)), - multiplier, - ) -} - -// Convert an integed amount of the default denomination to base units -func ApplyDefaultDenomination(amount uint64) *big.Int { - return ApplyDenomination(amount, defaultDenomination) -}