Skip to content

Commit

Permalink
poa acp99 + external evm signature support
Browse files Browse the repository at this point in the history
  • Loading branch information
felipemadero committed Mar 1, 2025
1 parent 6904684 commit 7b017c9
Show file tree
Hide file tree
Showing 25 changed files with 1,088 additions and 163 deletions.
18 changes: 13 additions & 5 deletions cmd/blockchaincmd/add_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ var (
aggregatorAllowPrivatePeers bool
clusterNameFlagValue string
createLocalValidator bool
multisigValidatorManagerOwner bool
externalValidatorManagerOwner bool
)

const (
Expand Down Expand Up @@ -126,7 +126,7 @@ Testnet or Mainnet.`,
cmd.Flags().StringVar(&subnetIDstr, "subnet-id", "", "subnet ID (only if blockchain name is not provided)")
cmd.Flags().StringVar(&validatorManagerOwnerAddress, "validator-manager-owner", "", "validator manager owner address (only if blockchain name is not provided)")
cmd.Flags().Uint64Var(&weight, validatorWeightFlag, uint64(constants.DefaultStakeWeight), "set the weight of the validator")
cmd.Flags().BoolVar(&multisigValidatorManagerOwner, "multisig-validator-manager-ower", false, "validator manager owner is multisig, make hex dump of ech evm transactions, so they can be signed in a separate flow")
cmd.Flags().BoolVar(&externalValidatorManagerOwner, "external-validator-manager-owner", false, "validator manager owner is external, make hex dump of ech evm transactions, so they can be signed in a separate flow")

return cmd
}
Expand Down Expand Up @@ -409,7 +409,7 @@ func CallAddValidator(
validatorManagerAddress = sc.Networks[network.Name()].ValidatorManagerAddress

var ownerPrivateKey string
if !multisigValidatorManagerOwner {
if !externalValidatorManagerOwner {
var ownerPrivateKeyFound bool
ownerPrivateKeyFound, _, _, ownerPrivateKey, err = contract.SearchForManagedKey(
app,
Expand All @@ -436,6 +436,13 @@ func CallAddValidator(
}
}
}

if sc.UseACP99 {
ux.Logger.PrintToUser(logging.Yellow.Wrap("Validator Manager Protocol: ACP99"))
} else {
ux.Logger.PrintToUser(logging.Yellow.Wrap("Validator Manager Protocol: v1.0.0"))
}

ux.Logger.PrintToUser(logging.Yellow.Wrap("Validation manager owner %s pays for the initialization of the validator's registration (Blockchain gas token)"), sc.ValidatorManagerOwner)

if rpcURL == "" {
Expand Down Expand Up @@ -537,7 +544,7 @@ func CallAddValidator(
network,
rpcURL,
chainSpec,
multisigValidatorManagerOwner,
externalValidatorManagerOwner,
sc.ValidatorManagerOwner,
ownerPrivateKey,
nodeID,
Expand All @@ -553,6 +560,7 @@ func CallAddValidator(
delegationFee,
duration,
validatorManagerAddress,
sc.UseACP99,
)
if err != nil {
return err
Expand Down Expand Up @@ -591,7 +599,7 @@ func CallAddValidator(
network,
rpcURL,
chainSpec,
multisigValidatorManagerOwner,
externalValidatorManagerOwner,
sc.ValidatorManagerOwner,
ownerPrivateKey,
validationID,
Expand Down
184 changes: 182 additions & 2 deletions cmd/blockchaincmd/change_weight.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,34 @@
package blockchaincmd

import (
"encoding/hex"
"fmt"
"strings"

"github.com/ava-labs/avalanche-cli/pkg/blockchain"
"github.com/ava-labs/avalanche-cli/pkg/cobrautils"
"github.com/ava-labs/avalanche-cli/pkg/constants"
"github.com/ava-labs/avalanche-cli/pkg/contract"
"github.com/ava-labs/avalanche-cli/pkg/key"
"github.com/ava-labs/avalanche-cli/pkg/keychain"
"github.com/ava-labs/avalanche-cli/pkg/models"
"github.com/ava-labs/avalanche-cli/pkg/networkoptions"
"github.com/ava-labs/avalanche-cli/pkg/node"
"github.com/ava-labs/avalanche-cli/pkg/prompts"
"github.com/ava-labs/avalanche-cli/pkg/subnet"
"github.com/ava-labs/avalanche-cli/pkg/utils"
"github.com/ava-labs/avalanche-cli/pkg/ux"
"github.com/ava-labs/avalanche-cli/pkg/validatormanager"
sdkutils "github.com/ava-labs/avalanche-cli/sdk/utils"
"github.com/ava-labs/avalanche-cli/sdk/validator"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/crypto/bls"
"github.com/ava-labs/avalanchego/utils/formatting"
"github.com/ava-labs/avalanchego/utils/formatting/address"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/utils/units"

"github.com/ethereum/go-ethereum/common"
"github.com/spf13/cobra"
)

Expand All @@ -47,6 +56,12 @@ The L1 has to be a Proof of Authority L1.`,
cmd.Flags().StringVar(&nodeEndpoint, "node-endpoint", "", "gather node id/bls from publicly available avalanchego apis on the given endpoint")
cmd.Flags().BoolVarP(&useLedger, "ledger", "g", false, "use ledger instead of key (always true on mainnet, defaults to false on fuji/devnet)")
cmd.Flags().StringSliceVar(&ledgerAddresses, "ledger-addrs", []string{}, "use the given ledger addresses")
cmd.Flags().BoolVar(&externalValidatorManagerOwner, "external-validator-manager-owner", false, "validator manager owner is external, make hex dump of ech evm transactions, so they can be signed in a separate flow")
cmd.Flags().StringSliceVar(&aggregatorExtraEndpoints, "aggregator-extra-endpoints", nil, "endpoints for extra nodes that are needed in signature aggregation")
cmd.Flags().BoolVar(&aggregatorAllowPrivatePeers, "aggregator-allow-private-peers", true, "allow the signature aggregator to connect to peers with private IP")
cmd.Flags().StringVar(&aggregatorLogLevel, "aggregator-log-level", constants.DefaultAggregatorLogLevel, "log level to use with signature aggregator")
cmd.Flags().BoolVar(&aggregatorLogToStdout, "aggregator-log-to-stdout", false, "use stdout for signature aggregator logs")
cmd.Flags().StringVar(&rpcURL, "rpc", "", "connect to validator manager at the given rpc endpoint")
return cmd
}

Expand Down Expand Up @@ -190,6 +205,21 @@ func setWeight(_ *cobra.Command, args []string) error {
return fmt.Errorf("can't make change: desired validator weight %d exceeds max allowed weight change of %d", newWeight, uint64(allowedChange))
}

deployer := subnet.NewPublicDeployer(app, kc, network)

if sc.UseACP99 {
ux.Logger.PrintToUser(logging.Yellow.Wrap("Validator Manager Protocol: ACP99"))
return changeWeightACP99(
deployer,
network,
blockchainName,
nodeID,
newWeight,
)
} else {
ux.Logger.PrintToUser(logging.Yellow.Wrap("Validator Manager Protocol: v1.0.0"))
}

publicKey, err = formatting.Encode(formatting.HexNC, bls.PublicKeyToCompressedBytes(validatorInfo.PublicKey))
if err != nil {
return err
Expand All @@ -202,8 +232,6 @@ func setWeight(_ *cobra.Command, args []string) error {
}
}

deployer := subnet.NewPublicDeployer(app, kc, network)

var remainingBalanceOwnerAddr, disableOwnerAddr string
hrp := key.GetHRP(network.ID)
if validatorInfo.RemainingBalanceOwner != nil && len(validatorInfo.RemainingBalanceOwner.Addrs) > 0 {
Expand Down Expand Up @@ -260,3 +288,155 @@ func setWeight(_ *cobra.Command, args []string) error {
sc,
)
}

func changeWeightACP99(
deployer *subnet.PublicDeployer,
network models.Network,
blockchainName string,
nodeID ids.NodeID,
weight uint64,
) error {
chainSpec := contract.ChainSpec{
BlockchainName: blockchainName,
}

sc, err := app.LoadSidecar(chainSpec.BlockchainName)
if err != nil {
return fmt.Errorf("failed to load sidecar: %w", err)
}
var ownerPrivateKey string
if !externalValidatorManagerOwner {
var ownerPrivateKeyFound bool
ownerPrivateKeyFound, _, _, ownerPrivateKey, err = contract.SearchForManagedKey(
app,
network,
common.HexToAddress(sc.ValidatorManagerOwner),
true,
)
if err != nil {
return err
}
if !ownerPrivateKeyFound {
return fmt.Errorf("not private key found for Validator manager owner %s", sc.ValidatorManagerOwner)
}
}
ux.Logger.PrintToUser(logging.Yellow.Wrap("Validator manager owner %s pays for the initialization of the validator's weight change (Blockchain gas token)"), sc.ValidatorManagerOwner)

if sc.Networks[network.Name()].ValidatorManagerAddress == "" {
return fmt.Errorf("unable to find Validator Manager address")
}
validatorManagerAddress = sc.Networks[network.Name()].ValidatorManagerAddress

ux.Logger.PrintToUser(logging.Yellow.Wrap("RPC Endpoint: %s"), rpcURL)

clusterName := sc.Networks[network.Name()].ClusterName
extraAggregatorPeers, err := blockchain.GetAggregatorExtraPeers(app, clusterName, aggregatorExtraEndpoints)
if err != nil {
return err
}
aggregatorLogger, err := utils.NewLogger(
constants.SignatureAggregatorLogName,
aggregatorLogLevel,
constants.DefaultAggregatorLogLevel,
app.GetAggregatorLogDir(clusterName),
aggregatorLogToStdout,
ux.Logger.PrintToUser,
)
if err != nil {
return err
}

aggregatorCtx, aggregatorCancel := sdkutils.GetTimedContext(constants.SignatureAggregatorTimeout)
defer aggregatorCancel()

// try to remove the validator. If err is "delegator ineligible for rewards" confirm with user and force remove
signedMessage, validationID, rawTx, err := validatormanager.InitValidatorWeightChange(
aggregatorCtx,
app,
network,
rpcURL,
chainSpec,
externalValidatorManagerOwner,
sc.ValidatorManagerOwner,
ownerPrivateKey,
nodeID,
extraAggregatorPeers,
aggregatorAllowPrivatePeers,
aggregatorLogger,
validatorManagerAddress,
weight,
)
if err != nil {
return err
}
if rawTx != nil {
bs, err := rawTx.MarshalBinary()
if err != nil {
return fmt.Errorf("failure marshalling raw evm tx: %w", err)
}
ux.Logger.PrintToUser("Raw Tx Dump For Initializing Validator Weight Change. Please sign and commit it.")
ux.Logger.PrintToUser("0x%s", hex.EncodeToString(bs))
return nil
}

ux.Logger.PrintToUser("ValidationID: %s", validationID)

validatorInfo, err := validator.GetValidatorInfo(network.SDKNetwork(), validationID)
if err != nil {
return err
}
if validatorInfo.Weight == newWeight {
ux.Logger.PrintToUser(logging.LightBlue.Wrap("The new Weight was already set on the P-Chain. Proceeding to the next step"))
} else {
txID, _, err := deployer.SetL1ValidatorWeight(signedMessage)
if err != nil {
if !strings.Contains(err.Error(), "could not load L1 validator: not found") {
return err
}
ux.Logger.PrintToUser(logging.LightBlue.Wrap("The Validation ID was already removed on the P-Chain. Proceeding to the next step"))
} else {
ux.Logger.PrintToUser("SetL1ValidatorWeightTx ID: %s", txID)
if err := blockchain.UpdatePChainHeight(
"Waiting for P-Chain to update validator information ...",
); err != nil {
return err
}
}
}

aggregatorCtx, aggregatorCancel = sdkutils.GetTimedContext(constants.SignatureAggregatorTimeout)
defer aggregatorCancel()
rawTx, err = validatormanager.FinishValidatorWeightChange(
aggregatorCtx,
app,
network,
rpcURL,
chainSpec,
externalValidatorManagerOwner,
sc.ValidatorManagerOwner,
ownerPrivateKey,
validationID,
extraAggregatorPeers,
aggregatorAllowPrivatePeers,
aggregatorLogger,
validatorManagerAddress,
signedMessage,
newWeight,
)
if err != nil {
return err
}
if rawTx != nil {
bs, err := rawTx.MarshalBinary()
if err != nil {
return fmt.Errorf("failure marshalling raw evm tx: %w", err)
}
ux.Logger.PrintToUser("Raw Tx Dump For Finish Validator Weight Change. Please sign and commit it.")
ux.Logger.PrintToUser("0x%s", hex.EncodeToString(bs))
return nil
}

ux.Logger.GreenCheckmarkToUser("Weight change successfully made")

return nil
}
9 changes: 9 additions & 0 deletions cmd/blockchaincmd/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,14 @@ func InitializeValidatorManager(
pos bool,
validatorManagerAddrStr string,
proxyContractOwner string,
useACP99 bool,
) (bool, error) {
if useACP99 {
ux.Logger.PrintToUser(logging.Yellow.Wrap("Validator Manager Protocol: ACP99"))
} else {
ux.Logger.PrintToUser(logging.Yellow.Wrap("Validator Manager Protocol: v1.0.0"))
}

var err error
clusterName := clusterNameFlagValue
switch {
Expand Down Expand Up @@ -403,6 +410,7 @@ func InitializeValidatorManager(
aggregatorAllowPrivatePeers,
aggregatorLogger,
validatorManagerAddrStr,
useACP99,
); err != nil {
return tracked, err
}
Expand Down Expand Up @@ -768,6 +776,7 @@ func convertBlockchain(_ *cobra.Command, args []string) error {
sidecar.ValidatorManagement == models.ProofOfStake,
validatorManagerAddress,
sidecar.ProxyContractOwner,
sidecar.UseACP99,
); err != nil {
return err
}
Expand Down
4 changes: 4 additions & 0 deletions cmd/blockchaincmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type CreateFlags struct {
validatorManagerOwner string
proxyContractOwner string
enableDebugging bool
useACP99 bool
}

var (
Expand Down Expand Up @@ -123,6 +124,7 @@ configuration, pass the -f flag.`,
cmd.Flags().BoolVar(&sovereign, "sovereign", true, "set to false if creating non-sovereign blockchain")
cmd.Flags().Uint64Var(&createFlags.rewardBasisPoints, "reward-basis-points", 100, "(PoS only) reward basis points for PoS Reward Calculator")
cmd.Flags().BoolVar(&createFlags.enableDebugging, "debug", true, "enable blockchain debugging")
cmd.Flags().BoolVar(&createFlags.useACP99, "acp99", true, "use ACP99 contracts instead of v1.0.0 for validator managers")
return cmd
}

Expand Down Expand Up @@ -335,6 +337,7 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error {
createFlags.addICMRegistryToGenesis,
sc.ProxyContractOwner,
createFlags.rewardBasisPoints,
createFlags.useACP99,
)
if err != nil {
return err
Expand All @@ -348,6 +351,7 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error {
tokenSymbol,
true,
sovereign,
createFlags.useACP99,
); err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions cmd/blockchaincmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,7 @@ func deployBlockchain(cmd *cobra.Command, args []string) error {
sidecar.ValidatorManagement == models.ProofOfStake,
validatorManagerStr,
sidecar.ProxyContractOwner,
sidecar.UseACP99,
)
if err != nil {
return err
Expand Down
5 changes: 5 additions & 0 deletions cmd/blockchaincmd/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,11 @@ func printSmartContracts(sc models.Sidecar, genesis core.Genesis) {
} else {
description = "Native Token Staking Manager"
}
if sc.UseACP99 {
description = "ACP99 Compatible " + description
} else {
description = "v1.0.0 Compatible " + description
}
case address == common.HexToAddress(validatorManagerSDK.ProxyContractAddress):
description = "Transparent Proxy"
case address == common.HexToAddress(validatorManagerSDK.ProxyAdminContractAddress):
Expand Down
1 change: 1 addition & 0 deletions cmd/blockchaincmd/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func TestExportImportSubnet(t *testing.T) {
"Test",
false,
true,
true,
)
require.NoError(err)
err = app.WriteGenesisFile(testSubnet, genBytes)
Expand Down
Loading

0 comments on commit 7b017c9

Please sign in to comment.