diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 198badfc5..a5edf0aed 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -45,8 +45,8 @@ jobs: source scripts/constants.sh go test ./... - e2e_tests: - name: e2e_tests + teleporter_e2e: + name: teleporter-e2e-tests runs-on: ubuntu-22.04 steps: - name: Checkout repositories and submodules @@ -67,15 +67,52 @@ jobs: run: | export PATH=$PATH:$HOME/.foundry/bin export PATH="$PATH:$GOPATH/bin" - ./scripts/local/e2e_test.sh + ./scripts/local/e2e_test.sh --components teleporter - - name: Upload tmpnet network dir - uses: actions/upload-artifact@v4 - if: always() + governance_e2e: + name: governance-e2e-tests + runs-on: ubuntu-22.04 + steps: + - name: Checkout repositories and submodules + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: 'go.mod' + + - name: Install Foundry + run: ./scripts/install_foundry.sh + + - name: Run E2E Tests + # Forge installs to BASE_DIR, but updates the PATH definition in $HOME/.bashrc + run: | + export PATH=$PATH:$HOME/.foundry/bin + export PATH="$PATH:$GOPATH/bin" + ./scripts/local/e2e_test.sh --components governance + + validator_manager_e2e: + name: validator-manager-e2e-tests + runs-on: ubuntu-22.04 + steps: + - name: Checkout repositories and submodules + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup Go + uses: actions/setup-go@v5 with: - name: e2e-tmpnet-data - path: | - ~/.tmpnet/networks - ~/.tmpnet/prometheus/prometheus.log - ~/.tmpnet/promtail/promtail.log - if-no-files-found: error + go-version-file: 'go.mod' + + - name: Install Foundry + run: ./scripts/install_foundry.sh + + - name: Run E2E Tests + # Forge installs to BASE_DIR, but updates the PATH definition in $HOME/.bashrc + run: | + export PATH=$PATH:$HOME/.foundry/bin + export PATH="$PATH:$GOPATH/bin" + ./scripts/local/e2e_test.sh --components validator-manager diff --git a/go.mod b/go.mod index 66f4080a7..e1679544d 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,12 @@ module github.com/ava-labs/teleporter go 1.22.8 require ( - github.com/ava-labs/avalanchego v1.12.0-initial-poc.3 + github.com/ava-labs/avalanchego v1.12.0-initial-poc.5 github.com/supranational/blst v0.3.11 // indirect ) require ( - github.com/ava-labs/awm-relayer v1.4.1-0.20241003183820-366b0dc8cea6 + github.com/ava-labs/awm-relayer v1.4.1-0.20241010161724-2db445c994d6 github.com/ava-labs/subnet-evm v0.6.10 github.com/ethereum/go-ethereum v1.13.14 github.com/onsi/ginkgo/v2 v2.20.2 @@ -19,6 +19,7 @@ require ( github.com/stretchr/testify v1.9.0 go.uber.org/zap v1.27.0 golang.org/x/tools v0.26.0 + google.golang.org/protobuf v1.35.1 ) require ( @@ -144,8 +145,7 @@ require ( gonum.org/v1/gonum v0.11.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect - google.golang.org/grpc v1.67.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/grpc v1.67.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index efbc45f68..761e8a12c 100644 --- a/go.sum +++ b/go.sum @@ -56,10 +56,10 @@ github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/ava-labs/avalanchego v1.12.0-initial-poc.3 h1:JfVooBCdMzpeGUT9/phJNl2GHflkGehlMJokXeWKa2A= -github.com/ava-labs/avalanchego v1.12.0-initial-poc.3/go.mod h1:qSHmog3wMVjo/ruIAQo0ppXAilyni07NIu5K88RyhWE= -github.com/ava-labs/awm-relayer v1.4.1-0.20241003183820-366b0dc8cea6 h1:v7k5wQxcvnYcMaz+zoO1OLAcU8REDD1EhfPZdl4Q+aI= -github.com/ava-labs/awm-relayer v1.4.1-0.20241003183820-366b0dc8cea6/go.mod h1:sSXpQtgiduMdZw5IVTSa1v418VCjb8GDLyrcGwJZ/HE= +github.com/ava-labs/avalanchego v1.12.0-initial-poc.5 h1:gW4xAqZNvkA4gP8M9yDyd7YUzuwfQbbCR+hgd1ztOto= +github.com/ava-labs/avalanchego v1.12.0-initial-poc.5/go.mod h1:qSHmog3wMVjo/ruIAQo0ppXAilyni07NIu5K88RyhWE= +github.com/ava-labs/awm-relayer v1.4.1-0.20241010161724-2db445c994d6 h1:WdFWoZ8clWfTPp3cKyWYTsveMKW/0SQzWk8U1aCcdnw= +github.com/ava-labs/awm-relayer v1.4.1-0.20241010161724-2db445c994d6/go.mod h1:6eqh3V1Og40gXmZUOP6tCrlmMEcVuj9l737yYh1s8uw= github.com/ava-labs/coreth v0.13.8 h1:f14X3KgwHl9LwzfxlN6S4bbn5VA2rhEsNnHaRLSTo/8= github.com/ava-labs/coreth v0.13.8/go.mod h1:t3BSv/eQv0AlDPMfEDCMMoD/jq1RkUsbFzQAFg5qBcE= github.com/ava-labs/subnet-evm v0.6.10 h1:uIh6bFMA4GCMVMQ3agBPxTMlYHL8FBR5FrhMR+drfKI= @@ -991,8 +991,8 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= -google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1005,8 +1005,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/scripts/local/e2e_test.sh b/scripts/local/e2e_test.sh index f45c931d2..783a898f2 100755 --- a/scripts/local/e2e_test.sh +++ b/scripts/local/e2e_test.sh @@ -9,6 +9,55 @@ TELEPORTER_PATH=$( cd ../.. && pwd ) +function printHelp() { + echo "Usage: ./scripts/local/e2e_test.sh [--component component]" + echo "" + printUsage +} + +function printUsage() { + cat << EOF +Arguments: + --components component1,component2 Comma separated list of test suites to run. Valid components are: + $(echo $valid_components | tr ' ' '\n' | sort | tr '\n' ' ') + (default: all) +Options: + --help Print this help message +EOF +} + +valid_components=$(ls -d $TELEPORTER_PATH/tests/local/*/ | xargs -n 1 basename) +components= + +while [ $# -gt 0 ]; do + case "$1" in + --components) + if [[ $2 != --* ]]; then + components=$2 + else + echo "Invalid components $2" && printHelp && exit 1 + fi + shift;; + --help) + printHelp && exit 0 ;; + *) + echo "Invalid option: $1" && printHelp && exit 1;; + esac + shift +done + +# Run all suites if no component is provided +if [ -z "$components" ]; then + components=$valid_components +fi + +# Exit if invalid component is provided +for component in $(echo $components | tr ',' ' '); do + if [[ $valid_components != *$component* ]]; then + echo "Invalid component $component" && exit 1 + fi +done + source "$TELEPORTER_PATH"/scripts/constants.sh source "$TELEPORTER_PATH"/scripts/versions.sh @@ -38,15 +87,18 @@ cd "$TELEPORTER_PATH" # to install the ginkgo binary (required for test build and run) go install -v github.com/onsi/ginkgo/v2/ginkgo@${GINKGO_VERSION} -ginkgo build ./tests/local/ +for component in $(echo $components | tr ',' ' '); do + echo "Building e2e tests for $component" + ginkgo build ./tests/local/$component -# Run the tests -echo "Running e2e tests $RUN_E2E" -RUN_E2E=true ./tests/local/local.test \ - --ginkgo.vv \ - --ginkgo.label-filter=${GINKGO_LABEL_FILTER:-""} \ - --ginkgo.focus=${GINKGO_FOCUS:-""} \ - --ginkgo.trace + echo "Running e2e tests for $component" + RUN_E2E=true ./tests/local/$component/$component.test \ + --ginkgo.vv \ + --ginkgo.label-filter=${GINKGO_LABEL_FILTER:-""} \ + --ginkgo.focus=${GINKGO_FOCUS:-""} \ + --ginkgo.trace -echo "e2e tests passed" + echo "$component e2e tests passed" + echo "" +done exit 0 diff --git a/tests/flows/governance/validator_set_sig.go b/tests/flows/governance/validator_set_sig.go index c715c02f3..cb32a09e8 100644 --- a/tests/flows/governance/validator_set_sig.go +++ b/tests/flows/governance/validator_set_sig.go @@ -143,7 +143,7 @@ func ValidatorSetSig(network interfaces.LocalNetwork) { network.SetChainConfigs(chainConfigs) restartCtx, cancel := context.WithTimeout(ctx, time.Second*30) defer cancel() - network.RestartNodes(restartCtx, network.GetAllNodeIDs()) + network.RestartNodes(restartCtx, nil) // ************************************************************************************************ // Test Case 1: validatorChain (subnetB) != targetChain (subnetA) diff --git a/tests/flows/teleporter/registry/teleporter_registry.go b/tests/flows/teleporter/registry/teleporter_registry.go index bca4de651..d6d6c14dc 100644 --- a/tests/flows/teleporter/registry/teleporter_registry.go +++ b/tests/flows/teleporter/registry/teleporter_registry.go @@ -79,7 +79,7 @@ func TeleporterRegistry(network interfaces.LocalNetwork) { network.SetChainConfigs(chainConfigs) restartCtx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() - network.RestartNodes(restartCtx, network.GetAllNodeIDs()) + network.RestartNodes(restartCtx, nil) // Call addProtocolVersion on subnetB to register the new Teleporter version utils.AddProtocolVersionAndWaitForAcceptance( diff --git a/tests/flows/teleporter/relayer_modifies_message.go b/tests/flows/teleporter/relayer_modifies_message.go index 4011ebc6f..df9a77d43 100644 --- a/tests/flows/teleporter/relayer_modifies_message.go +++ b/tests/flows/teleporter/relayer_modifies_message.go @@ -71,7 +71,7 @@ func relayAlteredMessage( sendEvent, err := utils.GetEventFromLogs(sourceReceipt.Logs, source.TeleporterMessenger.ParseSendCrossChainMessage) Expect(err).Should(BeNil()) - signedWarpMessage := network.ConstructSignedWarpMessage(ctx, sourceReceipt, source, destination) + signedWarpMessage := utils.ConstructSignedWarpMessage(ctx, sourceReceipt, source, destination) // Construct the transaction to send the Warp message to the destination chain _, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/teleporter/validator_churn.go b/tests/flows/teleporter/validator_churn.go index 2f84c7552..8737c8770 100644 --- a/tests/flows/teleporter/validator_churn.go +++ b/tests/flows/teleporter/validator_churn.go @@ -53,7 +53,7 @@ func ValidatorChurn(network interfaces.LocalNetwork) { sentTeleporterMessage := sendEvent.Message // Construct the signed warp message - signedWarpMessage := network.ConstructSignedWarpMessage(ctx, receipt, subnetAInfo, subnetBInfo) + signedWarpMessage := utils.ConstructSignedWarpMessage(ctx, receipt, subnetAInfo, subnetBInfo) // // Modify the validator set on Subnet A diff --git a/tests/flows/validator-manager/erc20_delegation.go b/tests/flows/validator-manager/erc20_delegation.go deleted file mode 100644 index 5e1b25009..000000000 --- a/tests/flows/validator-manager/erc20_delegation.go +++ /dev/null @@ -1,214 +0,0 @@ -package staking - -import ( - "context" - "math/big" - - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/subnet-evm/accounts/abi/bind" - "github.com/ava-labs/teleporter/tests/interfaces" - "github.com/ava-labs/teleporter/tests/utils" - . "github.com/onsi/gomega" -) - -/* - * Registers a delegator with an ERC20 token staking validator on a subnet. The steps are as follows: - * - Deploy the ERCTokenStakingManager - * - Register a validator - * - Register a delegator - * - Deleist the delegator - * - * TODO: as delegation gets built out, this test will need to be updated to cover: - * - Delegator rewards - * - Implicit delegation end at validation end - */ -func ERC20Delegation(network interfaces.LocalNetwork) { - // Get the subnets info - cChainInfo := network.GetPrimaryNetworkInfo() - subnetAInfo, _ := utils.GetTwoSubnets(network) - _, fundedKey := network.GetFundedAccountInfo() - pChainInfo := utils.GetPChainInfo(cChainInfo) - - signatureAggregator := utils.NewSignatureAggregator( - cChainInfo.NodeURIs[0], - []ids.ID{ - subnetAInfo.SubnetID, - }, - ) - ctx := context.Background() - - // Deploy the staking manager contract - stakingManagerAddress, stakingManager, _, erc20 := utils.DeployAndInitializeERC20TokenStakingManager( - ctx, - fundedKey, - subnetAInfo, - pChainInfo, - ) - - // _ = utils.InitializeERC20TokenValidatorSet( - // ctx, - // fundedKey, - // subnetAInfo, - // pChainInfo, - // stakingManager, - // stakingManagerAddress, - // network, - // signatureAggregator, - // utils.DefaultMinStakeAmount*10, - // ) - - // - // Register a validator - // - var validationID ids.ID // To be used in the delisting step - validatorStake := new(big.Int).SetUint64(utils.DefaultMinStakeAmount) - validatorWeight, err := stakingManager.ValueToWeight( - &bind.CallOpts{}, - validatorStake, - ) - Expect(err).Should(BeNil()) - // validationID = utils.InitializeAndCompleteERC20ValidatorRegistration( - // ctx, - // network, - // signatureAggregator, - // fundedKey, - // subnetAInfo, - // pChainInfo, - // stakingManager, - // stakingManagerAddress, - // erc20, - // validatorStake, - // ) - - // // - // Register a delegator - // - var delegationID ids.ID - { - delegatorStake := big.NewInt(1e17) - delegatorWeight, err := stakingManager.ValueToWeight( - &bind.CallOpts{}, - delegatorStake, - ) - Expect(err).Should(BeNil()) - newValidatorWeight := validatorWeight + delegatorWeight - - nonce := uint64(1) - - receipt := utils.InitializeERC20DelegatorRegistration( - ctx, - fundedKey, - subnetAInfo, - validationID, - delegatorStake, - erc20, - stakingManagerAddress, - stakingManager, - ) - initRegistrationEvent, err := utils.GetEventFromLogs( - receipt.Logs, - stakingManager.ParseDelegatorAdded, - ) - Expect(err).Should(BeNil()) - delegationID = initRegistrationEvent.DelegationID - - // Gather subnet-evm Warp signatures for the SubnetValidatorWeightUpdateMessage & relay to the P-Chain - // (Sending to the P-Chain will be skipped for now) - signedWarpMessage := network.ConstructSignedWarpMessage(context.Background(), receipt, subnetAInfo, pChainInfo) - - // Validate the Warp message, (this will be done on the P-Chain in the future) - utils.ValidateSubnetValidatorWeightMessage( - signedWarpMessage, - validationID, - newValidatorWeight, - nonce, - ) - - // Construct a SubnetValidatorWeightUpdateMessage Warp message from the P-Chain - registrationSignedMessage := utils.ConstructSubnetValidatorWeightUpdateMessage( - validationID, - nonce, - newValidatorWeight, - subnetAInfo, - pChainInfo, - network, - signatureAggregator, - ) - - // Deliver the Warp message to the subnet - receipt = utils.CompleteERC20DelegatorRegistration( - ctx, - fundedKey, - delegationID, - subnetAInfo, - stakingManagerAddress, - registrationSignedMessage, - ) - // Check that the validator is registered in the staking contract - registrationEvent, err := utils.GetEventFromLogs( - receipt.Logs, - stakingManager.ParseDelegatorRegistered, - ) - Expect(err).Should(BeNil()) - Expect(registrationEvent.ValidationID[:]).Should(Equal(validationID[:])) - Expect(registrationEvent.DelegationID[:]).Should(Equal(delegationID[:])) - } - // - // Delist the delegator - // - { - nonce := uint64(2) - receipt := utils.InitializeEndERC20Delegation( - ctx, - fundedKey, - subnetAInfo, - stakingManager, - delegationID, - ) - delegatorRemovalEvent, err := utils.GetEventFromLogs( - receipt.Logs, - stakingManager.ParseDelegatorRemovalInitialized, - ) - Expect(err).Should(BeNil()) - Expect(delegatorRemovalEvent.ValidationID[:]).Should(Equal(validationID[:])) - Expect(delegatorRemovalEvent.DelegationID[:]).Should(Equal(delegationID[:])) - - // Gather subnet-evm Warp signatures for the SetSubnetValidatorWeightMessage & relay to the P-Chain - // (Sending to the P-Chain will be skipped for now) - signedWarpMessage := network.ConstructSignedWarpMessage(context.Background(), receipt, subnetAInfo, pChainInfo) - Expect(err).Should(BeNil()) - - // Validate the Warp message, (this will be done on the P-Chain in the future) - utils.ValidateSubnetValidatorWeightMessage(signedWarpMessage, validationID, validatorWeight, 2) - - // Construct a SubnetValidatorWeightUpdateMessage Warp message from the P-Chain - signedMessage := utils.ConstructSubnetValidatorWeightUpdateMessage( - validationID, - nonce, - validatorWeight, - subnetAInfo, - pChainInfo, - network, - signatureAggregator, - ) - - // Deliver the Warp message to the subnet - receipt = utils.CompleteEndERC20Delegation( - ctx, - fundedKey, - delegationID, - subnetAInfo, - stakingManagerAddress, - signedMessage, - ) - - // Check that the delegator has been delisted from the staking contract - registrationEvent, err := utils.GetEventFromLogs( - receipt.Logs, - stakingManager.ParseDelegationEnded, - ) - Expect(err).Should(BeNil()) - Expect(registrationEvent.ValidationID[:]).Should(Equal(validationID[:])) - Expect(registrationEvent.DelegationID[:]).Should(Equal(delegationID[:])) - } -} diff --git a/tests/flows/validator-manager/erc20_token_staking.go b/tests/flows/validator-manager/erc20_token_staking.go index 7b34c9a06..b720b475b 100644 --- a/tests/flows/validator-manager/erc20_token_staking.go +++ b/tests/flows/validator-manager/erc20_token_staking.go @@ -2,17 +2,12 @@ package staking import ( "context" - "sort" + "log" + "math/big" "time" - "github.com/ava-labs/avalanchego/api/info" "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/utils/formatting/address" - "github.com/ava-labs/avalanchego/utils/units" - "github.com/ava-labs/avalanchego/vms/platformvm/txs" - "github.com/ava-labs/avalanchego/vms/platformvm/warp/message" "github.com/ava-labs/subnet-evm/accounts/abi/bind" - subnetEvmUtils "github.com/ava-labs/subnet-evm/tests/utils" "github.com/ava-labs/teleporter/tests/interfaces" "github.com/ava-labs/teleporter/tests/utils" . "github.com/onsi/gomega" @@ -57,99 +52,17 @@ func ERC20TokenStakingManager(network interfaces.LocalNetwork) { pChainInfo, ) - var nodes []utils.Node - - for _, uri := range subnetAInfo.NodeURIs { - infoClient := info.NewClient(uri) - nodeID, nodePoP, err := infoClient.GetNodeID(ctx) - Expect(err).Should(BeNil()) - nodes = append(nodes, utils.Node{ - NodeID: nodeID, - NodePoP: nodePoP, - }) - - // Remove the current validators before converting the subnet - _, err = network.GetPChainWallet().IssueRemoveSubnetValidatorTx( - nodeID, - subnetAInfo.SubnetID, - ) - Expect(err).Should(BeNil()) - } - - // Sort the nodeIDs so that the subnet conversion ID matches the P-Chain - sort.Slice(nodes, func(i, j int) bool { - return string(nodes[i].NodeID.Bytes()) < string(nodes[j].NodeID.Bytes()) - }) - - weights := make([]uint64, len(nodes)) - totalWeight := uint64(len(nodes)-1) * units.Schmeckle - for i := 0; i < len(nodes)-1; i++ { - weights[i] = units.Schmeckle - totalWeight += units.Schmeckle - } - // Set the last node's weight such that removing any other node will not violate the churn limit - weights[len(nodes)-1] = 4 * totalWeight - - // TODONOW: issue a P-Chain ConvertSubnetTx - destAddrStr := "P-local18jma8ppw3nhx5r4ap8clazz0dps7rv5u00z96u" - destAddr, err := address.ParseToID(destAddrStr) - Expect(err).Should(BeNil()) - // vdrs := make([]*txs.ConvertSubnetValidator, len(nodes)) - // for i, node := range nodes { - // vdrs[i] = &txs.ConvertSubnetValidator{ - // NodeID: node.NodeID.Bytes(), - // Weight: weights[i], - // Balance: units.Avax * 100, - // Signer: *node.NodePoP, - // RemainingBalanceOwner: message.PChainOwner{ - // Threshold: 1, - // Addresses: []ids.ShortID{destAddr}, - // }, - // DeactivationOwner: message.PChainOwner{ - // Threshold: 1, - // Addresses: []ids.ShortID{destAddr}, - // }, - // } - // } - - // Set just the last node (with a high weight) to the initial validator list - vdrs := []*txs.ConvertSubnetValidator{ - { - NodeID: nodes[len(nodes)-1].NodeID.Bytes(), - Weight: weights[len(nodes)-1], - Balance: units.Avax * 100, - Signer: *nodes[len(nodes)-1].NodePoP, - RemainingBalanceOwner: message.PChainOwner{ - Threshold: 1, - Addresses: []ids.ShortID{destAddr}, - }, - DeactivationOwner: message.PChainOwner{ - Threshold: 1, - Addresses: []ids.ShortID{destAddr}, - }, - }, - } - - _, err = network.GetPChainWallet().IssueConvertSubnetTx( - subnetAInfo.SubnetID, - subnetAInfo.BlockchainID, - stakingManagerAddress[:], - vdrs, + nodes := utils.ConvertSubnet( + ctx, + subnetAInfo, + network, + stakingManagerAddress, + fundedKey, ) - Expect(err).Should(BeNil()) - - utils.PChainProposerVMWorkaround(network) - - // Issue txs on the subnet to advance the proposer vm - for i := 0; i < 5; i++ { - err = subnetEvmUtils.IssueTxsToActivateProposerVMFork( - ctx, subnetAInfo.EVMChainID, fundedKey, subnetAInfo.WSClient, - ) - Expect(err).Should(BeNil()) - } // Initialize the validator set on the subnet - _ = utils.InitializeERC20TokenValidatorSet( + log.Println("Initializing validator set") + initialValidationIDs := utils.InitializeERC20TokenValidatorSet( ctx, fundedKey, subnetAInfo, @@ -158,37 +71,29 @@ func ERC20TokenStakingManager(network interfaces.LocalNetwork) { stakingManagerAddress, network, signatureAggregator, - nodes[len(nodes)-1:], - weights[len(nodes)-1:], + nodes, ) - // Delisting an initial validator does not work due to the way Warp signatures are requested for initial validators // - // Delist one initial validators + // Delist one initial validator // - // utils.InitializeAndCompleteEndERC20Validation( - // ctx, - // network, - // signatureAggregator, - // fundedKey, - // subnetAInfo, - // pChainInfo, - // stakingManager, - // stakingManagerAddress, - // initialValidationIDs[0], - // weights[0], - // 1, - // ) + utils.InitializeAndCompleteEndInitialERC20Validation( + ctx, + network, + signatureAggregator, + fundedKey, + subnetAInfo, + pChainInfo, + stakingManager, + stakingManagerAddress, + initialValidationIDs[0], + 0, + nodes[0].Weight, + ) // - // Register a validator + // Register the validator as PoS // - stakeAmount, err := stakingManager.WeightToValue( - &bind.CallOpts{}, - weights[0], - ) - Expect(err).Should(BeNil()) - // TODONOW: pass the validatorID pre image to the signature aggregator expiry := uint64(time.Now().Add(24 * time.Hour).Unix()) validationID := utils.InitializeAndCompleteERC20ValidatorRegistration( ctx, @@ -200,12 +105,148 @@ func ERC20TokenStakingManager(network interfaces.LocalNetwork) { stakingManager, stakingManagerAddress, erc20, - stakeAmount, - weights[0], expiry, nodes[0], ) + // + // Register a delegator + // + var delegationID ids.ID + { + log.Println("Registering delegator") + delegatorStake, err := stakingManager.WeightToValue( + &bind.CallOpts{}, + nodes[0].Weight, + ) + Expect(err).Should(BeNil()) + delegatorStake.Div(delegatorStake, big.NewInt(10)) + delegatorWeight, err := stakingManager.ValueToWeight( + &bind.CallOpts{}, + delegatorStake, + ) + Expect(err).Should(BeNil()) + newValidatorWeight := nodes[0].Weight + delegatorWeight + + nonce := uint64(1) + + receipt := utils.InitializeERC20DelegatorRegistration( + ctx, + fundedKey, + subnetAInfo, + validationID, + delegatorStake, + erc20, + stakingManagerAddress, + stakingManager, + ) + initRegistrationEvent, err := utils.GetEventFromLogs( + receipt.Logs, + stakingManager.ParseDelegatorAdded, + ) + Expect(err).Should(BeNil()) + delegationID = initRegistrationEvent.DelegationID + + // Gather subnet-evm Warp signatures for the SubnetValidatorWeightUpdateMessage & relay to the P-Chain + signedWarpMessage := utils.ConstructSignedWarpMessage(context.Background(), receipt, subnetAInfo, pChainInfo) + + // Issue a tx to update the validator's weight on the P-Chain + network.GetPChainWallet().IssueSetSubnetValidatorWeightTx(signedWarpMessage.Bytes()) + utils.PChainProposerVMWorkaround(network) + utils.AdvanceProposerVM(ctx, subnetAInfo, fundedKey, 5) + + // Construct a SubnetValidatorWeightUpdateMessage Warp message from the P-Chain + registrationSignedMessage := utils.ConstructSubnetValidatorWeightUpdateMessage( + validationID, + nonce, + newValidatorWeight, + subnetAInfo, + pChainInfo, + network, + signatureAggregator, + ) + + // Deliver the Warp message to the subnet + receipt = utils.CompleteERC20DelegatorRegistration( + ctx, + fundedKey, + delegationID, + subnetAInfo, + stakingManagerAddress, + registrationSignedMessage, + ) + // Check that the validator is registered in the staking contract + registrationEvent, err := utils.GetEventFromLogs( + receipt.Logs, + stakingManager.ParseDelegatorRegistered, + ) + Expect(err).Should(BeNil()) + Expect(registrationEvent.ValidationID[:]).Should(Equal(validationID[:])) + Expect(registrationEvent.DelegationID[:]).Should(Equal(delegationID[:])) + } + + // + // Delist the delegator + // + { + log.Println("Delisting delegator") + nonce := uint64(2) + receipt := utils.InitializeEndERC20Delegation( + ctx, + fundedKey, + subnetAInfo, + stakingManager, + delegationID, + ) + delegatorRemovalEvent, err := utils.GetEventFromLogs( + receipt.Logs, + stakingManager.ParseDelegatorRemovalInitialized, + ) + Expect(err).Should(BeNil()) + Expect(delegatorRemovalEvent.ValidationID[:]).Should(Equal(validationID[:])) + Expect(delegatorRemovalEvent.DelegationID[:]).Should(Equal(delegationID[:])) + + // Gather subnet-evm Warp signatures for the SetSubnetValidatorWeightMessage & relay to the P-Chain + // (Sending to the P-Chain will be skipped for now) + signedWarpMessage := utils.ConstructSignedWarpMessage(context.Background(), receipt, subnetAInfo, pChainInfo) + Expect(err).Should(BeNil()) + + // Issue a tx to update the validator's weight on the P-Chain + network.GetPChainWallet().IssueSetSubnetValidatorWeightTx(signedWarpMessage.Bytes()) + utils.PChainProposerVMWorkaround(network) + utils.AdvanceProposerVM(ctx, subnetAInfo, fundedKey, 5) + + // Construct a SubnetValidatorWeightUpdateMessage Warp message from the P-Chain + signedMessage := utils.ConstructSubnetValidatorWeightUpdateMessage( + validationID, + nonce, + nodes[0].Weight, + subnetAInfo, + pChainInfo, + network, + signatureAggregator, + ) + + // Deliver the Warp message to the subnet + receipt = utils.CompleteEndERC20Delegation( + ctx, + fundedKey, + delegationID, + subnetAInfo, + stakingManagerAddress, + signedMessage, + ) + + // Check that the delegator has been delisted from the staking contract + registrationEvent, err := utils.GetEventFromLogs( + receipt.Logs, + stakingManager.ParseDelegationEnded, + ) + Expect(err).Should(BeNil()) + Expect(registrationEvent.ValidationID[:]).Should(Equal(validationID[:])) + Expect(registrationEvent.DelegationID[:]).Should(Equal(delegationID[:])) + } + // // Delist the validator // @@ -221,7 +262,6 @@ func ERC20TokenStakingManager(network interfaces.LocalNetwork) { validationID, expiry, nodes[0], - weights[0], 1, ) } diff --git a/tests/flows/validator-manager/native_delegation.go b/tests/flows/validator-manager/native_delegation.go deleted file mode 100644 index d584064d2..000000000 --- a/tests/flows/validator-manager/native_delegation.go +++ /dev/null @@ -1,214 +0,0 @@ -package staking - -import ( - "context" - "math/big" - - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/subnet-evm/accounts/abi/bind" - "github.com/ava-labs/teleporter/tests/interfaces" - "github.com/ava-labs/teleporter/tests/utils" - . "github.com/onsi/gomega" -) - -/* - * Registers a delegator with a native token staking validator on a subnet. The steps are as follows: - * - Deploy the NativeTokenStakingManager - * - Register a validator - * - Register a delegator - * - Deleist the delegator - * - * TODO: as delegation gets built out, this test will need to be updated to cover: - * - Delegator rewards - * - Implicit delegation end at validation end - */ -func NativeDelegation(network interfaces.LocalNetwork) { - // Get the subnets info - cChainInfo := network.GetPrimaryNetworkInfo() - subnetAInfo, _ := utils.GetTwoSubnets(network) - _, fundedKey := network.GetFundedAccountInfo() - pChainInfo := utils.GetPChainInfo(cChainInfo) - - signatureAggregator := utils.NewSignatureAggregator( - cChainInfo.NodeURIs[0], - []ids.ID{ - subnetAInfo.SubnetID, - }, - ) - ctx := context.Background() - - // Deploy the staking manager contract - stakingManagerAddress, stakingManager := utils.DeployAndInitializeNativeTokenStakingManager( - ctx, - fundedKey, - subnetAInfo, - pChainInfo, - ) - - utils.AddNativeMinterAdmin(ctx, subnetAInfo, fundedKey, stakingManagerAddress) - - _ = utils.InitializeNativeTokenValidatorSet( - ctx, - fundedKey, - subnetAInfo, - pChainInfo, - stakingManager, - stakingManagerAddress, - network, - signatureAggregator, - utils.DefaultMinStakeAmount*10, - ) - - // - // Register a validator - // - var validationID ids.ID // To be used in the delisting step - validatorStake := new(big.Int).SetUint64(utils.DefaultMinStakeAmount) - validatorWeight, err := stakingManager.ValueToWeight( - &bind.CallOpts{}, - validatorStake, - ) - Expect(err).Should(BeNil()) - stakeAmount := new(big.Int).SetUint64(utils.DefaultMinStakeAmount) - validationID = utils.InitializeAndCompleteNativeValidatorRegistration( - ctx, - network, - signatureAggregator, - fundedKey, - subnetAInfo, - pChainInfo, - stakingManager, - stakingManagerAddress, - stakeAmount, - ) - // - // Register a delegator - // - var delegationID ids.ID - { - delegatorStake := big.NewInt(1e17) - delegatorWeight, err := stakingManager.ValueToWeight( - &bind.CallOpts{}, - delegatorStake, - ) - Expect(err).Should(BeNil()) - newValidatorWeight := validatorWeight + delegatorWeight - - nonce := uint64(1) - - receipt := utils.InitializeNativeDelegatorRegistration( - ctx, - fundedKey, - subnetAInfo, - validationID, - delegatorStake, - stakingManagerAddress, - stakingManager, - ) - initRegistrationEvent, err := utils.GetEventFromLogs( - receipt.Logs, - stakingManager.ParseDelegatorAdded, - ) - Expect(err).Should(BeNil()) - delegationID = initRegistrationEvent.DelegationID - - // Gather subnet-evm Warp signatures for the SubnetValidatorWeightUpdateMessage & relay to the P-Chain - // (Sending to the P-Chain will be skipped for now) - signedWarpMessage := network.ConstructSignedWarpMessage(context.Background(), receipt, subnetAInfo, pChainInfo) - - // Validate the Warp message, (this will be done on the P-Chain in the future) - utils.ValidateSubnetValidatorWeightMessage( - signedWarpMessage, - validationID, - newValidatorWeight, - nonce, - ) - - // Construct a SubnetValidatorWeightUpdateMessage Warp message from the P-Chain - registrationSignedMessage := utils.ConstructSubnetValidatorWeightUpdateMessage( - validationID, - nonce, - newValidatorWeight, - subnetAInfo, - pChainInfo, - network, - signatureAggregator, - ) - - // Deliver the Warp message to the subnet - receipt = utils.CompleteNativeDelegatorRegistration( - ctx, - fundedKey, - delegationID, - subnetAInfo, - stakingManagerAddress, - registrationSignedMessage, - ) - // Check that the validator is registered in the staking contract - registrationEvent, err := utils.GetEventFromLogs( - receipt.Logs, - stakingManager.ParseDelegatorRegistered, - ) - Expect(err).Should(BeNil()) - Expect(registrationEvent.ValidationID[:]).Should(Equal(validationID[:])) - Expect(registrationEvent.DelegationID[:]).Should(Equal(delegationID[:])) - } - // - // Delist the delegator - // - { - nonce := uint64(2) - receipt := utils.InitializeEndNativeDelegation( - ctx, - fundedKey, - subnetAInfo, - stakingManager, - delegationID, - ) - delegatorRemovalEvent, err := utils.GetEventFromLogs( - receipt.Logs, - stakingManager.ParseDelegatorRemovalInitialized, - ) - Expect(err).Should(BeNil()) - Expect(delegatorRemovalEvent.ValidationID[:]).Should(Equal(validationID[:])) - Expect(delegatorRemovalEvent.DelegationID[:]).Should(Equal(delegationID[:])) - - // Gather subnet-evm Warp signatures for the SetSubnetValidatorWeightMessage & relay to the P-Chain - // (Sending to the P-Chain will be skipped for now) - signedWarpMessage := network.ConstructSignedWarpMessage(context.Background(), receipt, subnetAInfo, pChainInfo) - Expect(err).Should(BeNil()) - - // Validate the Warp message, (this will be done on the P-Chain in the future) - utils.ValidateSubnetValidatorWeightMessage(signedWarpMessage, validationID, validatorWeight, 2) - - // Construct a SubnetValidatorWeightUpdateMessage Warp message from the P-Chain - signedMessage := utils.ConstructSubnetValidatorWeightUpdateMessage( - validationID, - nonce, - validatorWeight, - subnetAInfo, - pChainInfo, - network, - signatureAggregator, - ) - - // Deliver the Warp message to the subnet - receipt = utils.CompleteEndNativeDelegation( - ctx, - fundedKey, - delegationID, - subnetAInfo, - stakingManagerAddress, - signedMessage, - ) - - // Check that the delegator has been delisted from the staking contract - registrationEvent, err := utils.GetEventFromLogs( - receipt.Logs, - stakingManager.ParseDelegationEnded, - ) - Expect(err).Should(BeNil()) - Expect(registrationEvent.ValidationID[:]).Should(Equal(validationID[:])) - Expect(registrationEvent.DelegationID[:]).Should(Equal(delegationID[:])) - } -} diff --git a/tests/flows/validator-manager/native_token_staking.go b/tests/flows/validator-manager/native_token_staking.go index f6ec14ba3..80a7961b0 100644 --- a/tests/flows/validator-manager/native_token_staking.go +++ b/tests/flows/validator-manager/native_token_staking.go @@ -2,7 +2,9 @@ package staking import ( "context" + "log" "math/big" + "time" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/subnet-evm/accounts/abi/bind" @@ -43,37 +45,58 @@ func NativeTokenStakingManager(network interfaces.LocalNetwork) { ctx := context.Background() // Deploy the staking manager contract - stakingManagerContractAddress, stakingManager := utils.DeployAndInitializeNativeTokenStakingManager( + stakingManagerAddress, stakingManager := utils.DeployAndInitializeNativeTokenStakingManager( ctx, fundedKey, subnetAInfo, pChainInfo, ) - utils.AddNativeMinterAdmin(ctx, subnetAInfo, fundedKey, stakingManagerContractAddress) + utils.AddNativeMinterAdmin(ctx, subnetAInfo, fundedKey, stakingManagerAddress) - _ = utils.InitializeNativeTokenValidatorSet( + nodes := utils.ConvertSubnet( + ctx, + subnetAInfo, + network, + stakingManagerAddress, + fundedKey, + ) + + // Initialize the validator set on the subnet + log.Println("Initializing validator set") + initialValidationIDs := utils.InitializeNativeTokenValidatorSet( ctx, fundedKey, subnetAInfo, pChainInfo, stakingManager, - stakingManagerContractAddress, + stakingManagerAddress, network, signatureAggregator, - utils.DefaultMinStakeAmount*10, + nodes, ) // - // Register a validator + // Delist one initial validator // - stakeAmount := new(big.Int).SetUint64(utils.DefaultMinStakeAmount) - weight, err := stakingManager.ValueToWeight( - &bind.CallOpts{}, - stakeAmount, + utils.InitializeAndCompleteEndInitialNativeValidation( + ctx, + network, + signatureAggregator, + fundedKey, + subnetAInfo, + pChainInfo, + stakingManager, + stakingManagerAddress, + initialValidationIDs[0], + 0, + nodes[0].Weight, ) - Expect(err).Should(BeNil()) - // Iniatiate validator registration + + // + // Register the validator as PoS + // + expiry := uint64(time.Now().Add(24 * time.Hour).Unix()) validationID := utils.InitializeAndCompleteNativeValidatorRegistration( ctx, network, @@ -82,10 +105,147 @@ func NativeTokenStakingManager(network interfaces.LocalNetwork) { subnetAInfo, pChainInfo, stakingManager, - stakingManagerContractAddress, - stakeAmount, + stakingManagerAddress, + expiry, + nodes[0], ) + // + // Register a delegator + // + var delegationID ids.ID + { + log.Println("Registering delegator") + delegatorStake, err := stakingManager.WeightToValue( + &bind.CallOpts{}, + nodes[0].Weight, + ) + Expect(err).Should(BeNil()) + delegatorStake.Div(delegatorStake, big.NewInt(10)) + delegatorWeight, err := stakingManager.ValueToWeight( + &bind.CallOpts{}, + delegatorStake, + ) + Expect(err).Should(BeNil()) + newValidatorWeight := nodes[0].Weight + delegatorWeight + + nonce := uint64(1) + + receipt := utils.InitializeNativeDelegatorRegistration( + ctx, + fundedKey, + subnetAInfo, + validationID, + delegatorStake, + stakingManagerAddress, + stakingManager, + ) + initRegistrationEvent, err := utils.GetEventFromLogs( + receipt.Logs, + stakingManager.ParseDelegatorAdded, + ) + Expect(err).Should(BeNil()) + delegationID = initRegistrationEvent.DelegationID + + // Gather subnet-evm Warp signatures for the SubnetValidatorWeightUpdateMessage & relay to the P-Chain + signedWarpMessage := utils.ConstructSignedWarpMessage(context.Background(), receipt, subnetAInfo, pChainInfo) + + // Issue a tx to update the validator's weight on the P-Chain + network.GetPChainWallet().IssueSetSubnetValidatorWeightTx(signedWarpMessage.Bytes()) + utils.PChainProposerVMWorkaround(network) + utils.AdvanceProposerVM(ctx, subnetAInfo, fundedKey, 5) + + // Construct a SubnetValidatorWeightUpdateMessage Warp message from the P-Chain + registrationSignedMessage := utils.ConstructSubnetValidatorWeightUpdateMessage( + validationID, + nonce, + newValidatorWeight, + subnetAInfo, + pChainInfo, + network, + signatureAggregator, + ) + + // Deliver the Warp message to the subnet + receipt = utils.CompleteNativeDelegatorRegistration( + ctx, + fundedKey, + delegationID, + subnetAInfo, + stakingManagerAddress, + registrationSignedMessage, + ) + // Check that the validator is registered in the staking contract + registrationEvent, err := utils.GetEventFromLogs( + receipt.Logs, + stakingManager.ParseDelegatorRegistered, + ) + Expect(err).Should(BeNil()) + Expect(registrationEvent.ValidationID[:]).Should(Equal(validationID[:])) + Expect(registrationEvent.DelegationID[:]).Should(Equal(delegationID[:])) + } + // + // Delist the delegator + // + { + log.Println("Delisting delegator") + nonce := uint64(2) + receipt := utils.InitializeEndNativeDelegation( + ctx, + fundedKey, + subnetAInfo, + stakingManager, + delegationID, + ) + delegatorRemovalEvent, err := utils.GetEventFromLogs( + receipt.Logs, + stakingManager.ParseDelegatorRemovalInitialized, + ) + Expect(err).Should(BeNil()) + Expect(delegatorRemovalEvent.ValidationID[:]).Should(Equal(validationID[:])) + Expect(delegatorRemovalEvent.DelegationID[:]).Should(Equal(delegationID[:])) + + // Gather subnet-evm Warp signatures for the SetSubnetValidatorWeightMessage & relay to the P-Chain + // (Sending to the P-Chain will be skipped for now) + signedWarpMessage := utils.ConstructSignedWarpMessage(context.Background(), receipt, subnetAInfo, pChainInfo) + Expect(err).Should(BeNil()) + + // Issue a tx to update the validator's weight on the P-Chain + network.GetPChainWallet().IssueSetSubnetValidatorWeightTx(signedWarpMessage.Bytes()) + utils.PChainProposerVMWorkaround(network) + utils.AdvanceProposerVM(ctx, subnetAInfo, fundedKey, 5) + + // Construct a SubnetValidatorWeightUpdateMessage Warp message from the P-Chain + signedMessage := utils.ConstructSubnetValidatorWeightUpdateMessage( + validationID, + nonce, + nodes[0].Weight, + subnetAInfo, + pChainInfo, + network, + signatureAggregator, + ) + + // Deliver the Warp message to the subnet + receipt = utils.CompleteEndNativeDelegation( + ctx, + fundedKey, + delegationID, + subnetAInfo, + stakingManagerAddress, + signedMessage, + ) + + // Check that the delegator has been delisted from the staking contract + registrationEvent, err := utils.GetEventFromLogs( + receipt.Logs, + stakingManager.ParseDelegationEnded, + ) + Expect(err).Should(BeNil()) + Expect(registrationEvent.ValidationID[:]).Should(Equal(validationID[:])) + Expect(registrationEvent.DelegationID[:]).Should(Equal(delegationID[:])) + } + // // Delist the validator // @@ -97,9 +257,10 @@ func NativeTokenStakingManager(network interfaces.LocalNetwork) { subnetAInfo, pChainInfo, stakingManager, - stakingManagerContractAddress, + stakingManagerAddress, validationID, - weight, + expiry, + nodes[0], 1, ) } diff --git a/tests/flows/validator-manager/poa_to_pos.go b/tests/flows/validator-manager/poa_to_pos.go index af2bb8072..9cce8b401 100644 --- a/tests/flows/validator-manager/poa_to_pos.go +++ b/tests/flows/validator-manager/poa_to_pos.go @@ -2,7 +2,9 @@ package staking import ( "context" + "log" "math/big" + "time" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/subnet-evm/accounts/abi/bind" @@ -54,7 +56,8 @@ func PoAMigrationToPoS(network interfaces.LocalNetwork) { // Transfer native assets to the owner account ctx := context.Background() - fundAmount := big.NewInt(1e18) // 1avax + fundAmount := big.NewInt(1e18) // 10avax + fundAmount.Mul(fundAmount, big.NewInt(10)) utils.SendNativeTransfer( ctx, subnetAInfo, @@ -96,7 +99,17 @@ func PoAMigrationToPoS(network interfaces.LocalNetwork) { Expect(err).Should(BeNil()) utils.WaitForTransactionSuccess(context.Background(), subnetAInfo, tx.Hash()) - _ = utils.InitializePoAValidatorSet( + nodes := utils.ConvertSubnet( + ctx, + subnetAInfo, + network, + proxyAddress, + fundedKey, + ) + + // Initialize the validator set on the subnet + log.Println("Initializing validator set") + initialValidationIDs := utils.InitializePoAValidatorSet( ctx, fundedKey, subnetAInfo, @@ -105,11 +118,46 @@ func PoAMigrationToPoS(network interfaces.LocalNetwork) { proxyAddress, network, signatureAggregator, - utils.DefaultMinStakeAmount*10, + nodes, + ) + + // + // Delist one initial validator + // + utils.InitializeAndCompleteEndInitialPoAValidation( + ctx, + network, + signatureAggregator, + ownerKey, + fundedKey, + subnetAInfo, + pChainInfo, + poaValidatorManager, + proxyAddress, + initialValidationIDs[0], + 0, + nodes[0].Weight, + ) + + // Try to call with invalid owner + opts, err = bind.NewKeyedTransactorWithChainID(fundedKey, subnetAInfo.EVMChainID) + Expect(err).Should(BeNil()) + + _, err = poaValidatorManager.InitializeValidatorRegistration( + opts, + poavalidatormanager.ValidatorRegistrationInput{ + NodeID: nodes[0].NodeID[:], + RegistrationExpiry: uint64(time.Now().Add(24 * time.Hour).Unix()), + BlsPublicKey: nodes[0].NodePoP.PublicKey[:], + }, + nodes[0].Weight, ) + Expect(err).ShouldNot(BeNil()) - // Register a validator - poaWeight := uint64(1) + // + // Re-register the validator as a SoV validator + // + expiry := uint64(time.Now().Add(24 * time.Hour).Unix()) poaValidationID := utils.InitializeAndCompletePoAValidatorRegistration( ctx, network, @@ -120,7 +168,8 @@ func PoAMigrationToPoS(network interfaces.LocalNetwork) { pChainInfo, poaValidatorManager, proxyAddress, - poaWeight, + expiry, + nodes[0], ) poaValidator, err := poaValidatorManager.GetValidator(&bind.CallOpts{}, poaValidationID) Expect(err).Should(BeNil()) @@ -184,39 +233,37 @@ func PoAMigrationToPoS(network interfaces.LocalNetwork) { Expect(err).Should(BeNil()) Expect(validationID[:]).Should(Equal(poaValidationID[:])) - // Register a PoS validator - stakeAmount := big.NewInt(1e18) - posWeight, err := posValidatorManager.ValueToWeight( - &bind.CallOpts{}, - stakeAmount, - ) - Expect(err).Should(BeNil()) + // + // Remove the PoA validator and re-register as a PoS validator + // - posValidationID := utils.InitializeAndCompleteNativeValidatorRegistration( + utils.InitializeAndCompleteEndNativeValidation( ctx, network, signatureAggregator, - fundedKey, + ownerKey, subnetAInfo, pChainInfo, posValidatorManager, proxyAddress, - stakeAmount, + poaValidationID, + expiry, + nodes[0], + 1, ) - // Delist the previous PoA validator - utils.InitializeAndCompleteEndNativeValidation( + expiry2 := uint64(time.Now().Add(24 * time.Hour).Unix()) + posValidationID := utils.InitializeAndCompleteNativeValidatorRegistration( ctx, network, signatureAggregator, - ownerKey, + fundedKey, subnetAInfo, pChainInfo, posValidatorManager, proxyAddress, - poaValidationID, - poaWeight, - 1, + expiry2, + nodes[0], ) // Delist the PoS validator @@ -230,7 +277,8 @@ func PoAMigrationToPoS(network interfaces.LocalNetwork) { posValidatorManager, proxyAddress, posValidationID, - posWeight, + expiry2, + nodes[0], 1, ) } diff --git a/tests/flows/validator-manager/poa_validator_manager.go b/tests/flows/validator-manager/poa_validator_manager.go deleted file mode 100644 index a7733b449..000000000 --- a/tests/flows/validator-manager/poa_validator_manager.go +++ /dev/null @@ -1,150 +0,0 @@ -package staking - -import ( - "context" - "math/big" - "time" - - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/utils/crypto/bls" - "github.com/ava-labs/subnet-evm/accounts/abi/bind" - poavalidatormanager "github.com/ava-labs/teleporter/abi-bindings/go/validator-manager/PoAValidatorManager" - "github.com/ava-labs/teleporter/tests/interfaces" - "github.com/ava-labs/teleporter/tests/utils" - "github.com/ethereum/go-ethereum/crypto" - . "github.com/onsi/gomega" -) - -/* - * Register a PoA validator manager on a L1. The steps are as follows: - * - Generate random address to be the owner address - * - Fund native assets to the owner address - * - Deploy the PoAValidatorManager contract - * - Attempt to initiate with non owner and check that it fails - * - Initiate validator registration - * - Deliver the Warp message to the P-Chain (not implemented) - * - Aggregate P-Chain signatures on the response Warp message - * - Deliver the Warp message to the L1 - * - Verify that the validator is registered in the validator manager contract - * - * Delists the validator from the L1. The steps are as follows: - * - Attempt to initiate with non owner and check that it fails - * - Initiate validator delisting - * - Deliver the Warp message to the P-Chain (not implemented) - * - Aggregate P-Chain signatures on the response Warp message - * - Deliver the Warp message to the L1 - * - Verify that the validator is delisted from the validator manager contract - */ -func PoAValidatorManager(network interfaces.LocalNetwork) { - cChainInfo := network.GetPrimaryNetworkInfo() - subnetAInfo, _ := utils.GetTwoSubnets(network) - _, fundedKey := network.GetFundedAccountInfo() - pChainInfo := utils.GetPChainInfo(cChainInfo) - - signatureAggregator := utils.NewSignatureAggregator( - cChainInfo.NodeURIs[0], - []ids.ID{ - subnetAInfo.SubnetID, - }, - ) - - // Generate random address to be the owner address - ownerKey, err := crypto.GenerateKey() - Expect(err).Should(BeNil()) - ownerAddress := crypto.PubkeyToAddress(ownerKey.PublicKey) - - // Transfer native assets to the owner account - ctx := context.Background() - fundAmount := big.NewInt(1e18) // 1avax - utils.SendNativeTransfer( - ctx, - subnetAInfo, - fundedKey, - ownerAddress, - fundAmount, - ) - - validatorManagerAddress, validatorManager := utils.DeployAndInitializePoAValidatorManager( - ctx, - fundedKey, - subnetAInfo, - pChainInfo, - ownerAddress, - ) - _ = utils.InitializePoAValidatorSet( - ctx, - fundedKey, - subnetAInfo, - pChainInfo, - validatorManager, - validatorManagerAddress, - network, - signatureAggregator, - 5, - ) - - var validationID ids.ID // To be used in the delisting step - weight := uint64(1) - - { - // Try to call with invalid owner - opts, err := bind.NewKeyedTransactorWithChainID(fundedKey, subnetAInfo.EVMChainID) - Expect(err).Should(BeNil()) - - nodeID := ids.GenerateTestID() - blsPublicKey := [bls.PublicKeyLen]byte{} - _, err = validatorManager.InitializeValidatorRegistration( - opts, - poavalidatormanager.ValidatorRegistrationInput{ - NodeID: nodeID[:], - RegistrationExpiry: uint64(time.Now().Add(24 * time.Hour).Unix()), - BlsPublicKey: blsPublicKey[:], - }, - weight, - ) - Expect(err).ShouldNot(BeNil()) - - // Initiate validator registration - validationID = utils.InitializeAndCompletePoAValidatorRegistration( - ctx, - network, - signatureAggregator, - ownerKey, - fundedKey, - subnetAInfo, - pChainInfo, - validatorManager, - validatorManagerAddress, - weight, - ) - } - - // - // Delist the validator - // - { - // Try with invalid validator owner - opts, err := bind.NewKeyedTransactorWithChainID(fundedKey, subnetAInfo.EVMChainID) - Expect(err).Should(BeNil()) - _, err = validatorManager.InitializeEndValidation( - opts, - validationID, - ) - Expect(err).ShouldNot(BeNil()) - - utils.InitializeAndCompleteEndPoAValidation( - ctx, - network, - signatureAggregator, - ownerKey, - fundedKey, - subnetAInfo, - pChainInfo, - validatorManager, - validatorManagerAddress, - validationID, - weight, - 1, - ) - } -} diff --git a/tests/interfaces/local_network.go b/tests/interfaces/local_network.go index 80b72f095..7b9e6aa7e 100644 --- a/tests/interfaces/local_network.go +++ b/tests/interfaces/local_network.go @@ -5,27 +5,13 @@ import ( "crypto/ecdsa" "github.com/ava-labs/avalanchego/ids" - avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" pwallet "github.com/ava-labs/avalanchego/wallet/chain/p/wallet" - "github.com/ava-labs/subnet-evm/core/types" "github.com/ethereum/go-ethereum/common" ) type LocalNetwork interface { Network AddSubnetValidators(ctx context.Context, subnetID ids.ID, count uint) - ExtractWarpMessageFromLog( - ctx context.Context, - sourceReceipt *types.Receipt, - source SubnetTestInfo, - ) *avalancheWarp.UnsignedMessage - ConstructSignedWarpMessage( - ctx context.Context, - sourceReceipt *types.Receipt, - source SubnetTestInfo, - destination SubnetTestInfo, - ) *avalancheWarp.Message - GetAllNodeIDs() []ids.NodeID SetChainConfigs(chainConfigs map[string]string) RestartNodes(ctx context.Context, nodeIDs []ids.NodeID) DeployTeleporterContractToCChain( @@ -41,6 +27,5 @@ type LocalNetwork interface { fundedKey *ecdsa.PrivateKey, ) GetNetworkID() uint32 - Dir() string GetPChainWallet() pwallet.Wallet } diff --git a/tests/interfaces/network.go b/tests/interfaces/network.go index f71afdfef..7bd84b60c 100644 --- a/tests/interfaces/network.go +++ b/tests/interfaces/network.go @@ -4,8 +4,6 @@ import ( "context" "crypto/ecdsa" - "github.com/ava-labs/avalanchego/ids" - avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/subnet-evm/core/types" "github.com/ethereum/go-ethereum/common" ) @@ -41,14 +39,6 @@ type Network interface { // connections with each validator. SupportsIndependentRelaying() bool - // GetSignedMessage returns the signed Warp message for the specified Warp message ID. - GetSignedMessage( - ctx context.Context, - source SubnetTestInfo, - destination SubnetTestInfo, - messageID ids.ID, - ) *avalancheWarp.Message - // For implementations where SupportsIndependentRelaying() is true, relays the specified message between the // two subnets,and returns the receipt of the transaction the message was delivered in. // For implementations where SupportsIndependentRelaying() is false, waits for the specific message to be relayed diff --git a/tests/local/e2e_test.go b/tests/local/e2e_test.go deleted file mode 100644 index aad4ccefa..000000000 --- a/tests/local/e2e_test.go +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (C) 2023, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package local - -import ( - "context" - "os" - "testing" - "time" - - validatorManager "github.com/ava-labs/teleporter/tests/flows/validator-manager" - deploymentUtils "github.com/ava-labs/teleporter/utils/deployment-utils" - "github.com/ethereum/go-ethereum/log" - "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -const ( - teleporterByteCodeFile = "./out/TeleporterMessenger.sol/TeleporterMessenger.json" - warpGenesisTemplateFile = "./tests/utils/warp-genesis-template.json" - - teleporterMessengerLabel = "TeleporterMessenger" - upgradabilityLabel = "upgradability" - utilsLabel = "utils" - validatorSetSigLabel = "ValidatorSetSig" - validatorManagerLabel = "ValidatorManager" -) - -var ( - LocalNetworkInstance *LocalNetwork -) - -func TestE2E(t *testing.T) { - if os.Getenv("RUN_E2E") == "" { - t.Skip("Environment variable RUN_E2E not set; skipping E2E tests") - } - - RegisterFailHandler(ginkgo.Fail) - ginkgo.RunSpecs(t, "Teleporter e2e test") -} - -// Define the Teleporter before and after suite functions. -var _ = ginkgo.BeforeSuite(func() { - // Generate the Teleporter deployment values - teleporterDeployerTransaction, teleporterDeployedBytecode, teleporterDeployerAddress, teleporterContractAddress, err := - deploymentUtils.ConstructKeylessTransaction( - teleporterByteCodeFile, - false, - deploymentUtils.GetDefaultContractCreationGasPrice(), - ) - Expect(err).Should(BeNil()) - - // Create the local network instance - ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) - defer cancel() - LocalNetworkInstance = NewLocalNetwork( - ctx, - "teleporter-test-local-network", - warpGenesisTemplateFile, - []SubnetSpec{ - { - Name: "A", - EVMChainID: 12345, - TeleporterContractAddress: teleporterContractAddress, - TeleporterDeployedBytecode: teleporterDeployedBytecode, - TeleporterDeployerAddress: teleporterDeployerAddress, - NodeCount: 2, - }, - { - Name: "B", - EVMChainID: 54321, - TeleporterContractAddress: teleporterContractAddress, - TeleporterDeployedBytecode: teleporterDeployedBytecode, - TeleporterDeployerAddress: teleporterDeployerAddress, - NodeCount: 2, - }, - }, - 2, - ) - log.Info("Started local network") - - // Only need to deploy Teleporter on the C-Chain since it is included in the genesis of the subnet chains. - _, fundedKey := LocalNetworkInstance.GetFundedAccountInfo() - LocalNetworkInstance.DeployTeleporterContractToCChain( - teleporterDeployerTransaction, - teleporterDeployerAddress, - teleporterContractAddress, - fundedKey, - ) - LocalNetworkInstance.SetTeleporterContractAddress(teleporterContractAddress) - - // Deploy the Teleporter registry contracts to all subnets and the C-Chain. - LocalNetworkInstance.DeployTeleporterRegistryContracts(teleporterContractAddress, fundedKey) - - ginkgo.AddReportEntry( - "network directory with node logs & configs; useful in the case of failures", - LocalNetworkInstance.tmpnet.Dir, - ginkgo.ReportEntryVisibilityFailureOrVerbose, - ) - - log.Info("Set up ginkgo before suite") -}) - -var _ = ginkgo.AfterSuite(func() { - LocalNetworkInstance.TearDownNetwork() -}) - -var _ = ginkgo.Describe("[Teleporter integration tests]", func() { - // // Teleporter tests - // ginkgo.It("Send a message from Subnet A to Subnet B, and one from B to A", - // ginkgo.Label(teleporterMessengerLabel), - // func() { - // teleporter.BasicSendReceive(LocalNetworkInstance) - // }) - // ginkgo.It("Deliver to the wrong chain", - // ginkgo.Label(teleporterMessengerLabel), - // func() { - // teleporter.DeliverToWrongChain(LocalNetworkInstance) - // }) - // ginkgo.It("Deliver to non-existent contract", - // ginkgo.Label(teleporterMessengerLabel), - // func() { - // teleporter.DeliverToNonExistentContract(LocalNetworkInstance) - // }) - // ginkgo.It("Retry successful execution", - // ginkgo.Label(teleporterMessengerLabel), - // func() { - // teleporter.RetrySuccessfulExecution(LocalNetworkInstance) - // }) - // ginkgo.It("Unallowed relayer", - // ginkgo.Label(teleporterMessengerLabel), - // func() { - // teleporter.UnallowedRelayer(LocalNetworkInstance) - // }) - // ginkgo.It("Relay message twice", - // ginkgo.Label(teleporterMessengerLabel), - // func() { - // teleporter.RelayMessageTwice(LocalNetworkInstance) - // }) - // ginkgo.It("Add additional fee amount", - // ginkgo.Label(teleporterMessengerLabel), - // func() { - // teleporter.AddFeeAmount(LocalNetworkInstance) - // }) - // ginkgo.It("Send specific receipts", - // ginkgo.Label(teleporterMessengerLabel), - // func() { - // teleporter.SendSpecificReceipts(LocalNetworkInstance) - // }) - // ginkgo.It("Insufficient gas", - // ginkgo.Label(teleporterMessengerLabel), - // func() { - // teleporter.InsufficientGas(LocalNetworkInstance) - // }) - // ginkgo.It("Resubmit altered message", - // ginkgo.Label(teleporterMessengerLabel), - // func() { - // teleporter.ResubmitAlteredMessage(LocalNetworkInstance) - // }) - // ginkgo.It("Calculate Teleporter message IDs", - // ginkgo.Label(utilsLabel), - // func() { - // teleporter.CalculateMessageID(LocalNetworkInstance) - // }) - // ginkgo.It("Relayer modifies message", - // ginkgo.Label(teleporterMessengerLabel), - // func() { - // teleporter.RelayerModifiesMessage(LocalNetworkInstance) - // }) - // ginkgo.It("Validator churn", - // ginkgo.Label(teleporterMessengerLabel), - // func() { - // teleporter.ValidatorChurn(LocalNetworkInstance) - // }) - - // // Teleporter Registry tests - // ginkgo.It("Teleporter registry", - // ginkgo.Label(upgradabilityLabel), - // func() { - // registry.TeleporterRegistry(LocalNetworkInstance) - // }) - // ginkgo.It("Check upgrade access", - // ginkgo.Label(upgradabilityLabel), - // func() { - // registry.CheckUpgradeAccess(LocalNetworkInstance) - // }) - // ginkgo.It("Pause and Unpause Teleporter", - // ginkgo.Label(upgradabilityLabel), - // func() { - // registry.PauseTeleporter(LocalNetworkInstance) - // }) - - // // Governance tests - // ginkgo.It("Deliver ValidatorSetSig signed message", - // ginkgo.Label(validatorSetSigLabel), - // func() { - // governance.ValidatorSetSig(LocalNetworkInstance) - // }) - - // // Validator Manager tests - // ginkgo.It("Native token staking manager", - // ginkgo.Label(validatorManagerLabel), - // func() { - // validatorManager.NativeTokenStakingManager(LocalNetworkInstance) - // }) - ginkgo.It("ERC20 token staking manager", - ginkgo.Label(validatorManagerLabel), - func() { - validatorManager.ERC20TokenStakingManager(LocalNetworkInstance) - }) - // ginkgo.It("PoA validator manager", - // ginkgo.Label(validatorManagerLabel), - // func() { - // validatorManager.PoAValidatorManager(LocalNetworkInstance) - // }) - // ginkgo.It("ERC20 delegation", - // ginkgo.Label(validatorManagerLabel), - // func() { - // validatorManager.ERC20Delegation(LocalNetworkInstance) - // }) - // ginkgo.It("Native token delegation", - // ginkgo.Label(validatorManagerLabel), - // func() { - // validatorManager.NativeDelegation(LocalNetworkInstance) - // }) - // ginkgo.It("PoA migration to PoS", - // ginkgo.Label(validatorManagerLabel), - // func() { - // validatorManager.PoAMigrationToPoS(LocalNetworkInstance) - // }) -}) diff --git a/tests/local/governance/governance_suite_test.go b/tests/local/governance/governance_suite_test.go new file mode 100644 index 000000000..f157dc224 --- /dev/null +++ b/tests/local/governance/governance_suite_test.go @@ -0,0 +1,93 @@ +package governance_test + +import ( + "context" + "os" + "testing" + "time" + + governanceFlows "github.com/ava-labs/teleporter/tests/flows/governance" + "github.com/ava-labs/teleporter/tests/local" + deploymentUtils "github.com/ava-labs/teleporter/utils/deployment-utils" + "github.com/ethereum/go-ethereum/log" + "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +const ( + teleporterByteCodeFile = "./out/TeleporterMessenger.sol/TeleporterMessenger.json" + warpGenesisTemplateFile = "./tests/utils/warp-genesis-template.json" + + teleporterMessengerLabel = "TeleporterMessenger" + upgradabilityLabel = "upgradability" + utilsLabel = "utils" + validatorSetSigLabel = "ValidatorSetSig" + validatorManagerLabel = "ValidatorManager" +) + +var ( + LocalNetworkInstance *local.LocalNetwork +) + +func TestGovernance(t *testing.T) { + if os.Getenv("RUN_E2E") == "" { + t.Skip("Environment variable RUN_E2E not set; skipping E2E tests") + } + + RegisterFailHandler(ginkgo.Fail) + ginkgo.RunSpecs(t, "Teleporter e2e test") +} + +// Define the Teleporter before and after suite functions. +var _ = ginkgo.BeforeSuite(func() { + // Generate the Teleporter deployment values + _, teleporterDeployedBytecode, teleporterDeployerAddress, teleporterContractAddress, err := + deploymentUtils.ConstructKeylessTransaction( + teleporterByteCodeFile, + false, + deploymentUtils.GetDefaultContractCreationGasPrice(), + ) + Expect(err).Should(BeNil()) + + // Create the local network instance + ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) + defer cancel() + LocalNetworkInstance = local.NewLocalNetwork( + ctx, + "teleporter-test-local-network", + warpGenesisTemplateFile, + []local.SubnetSpec{ + { + Name: "A", + EVMChainID: 12345, + TeleporterContractAddress: teleporterContractAddress, + TeleporterDeployedBytecode: teleporterDeployedBytecode, + TeleporterDeployerAddress: teleporterDeployerAddress, + NodeCount: 2, + }, + { + Name: "B", + EVMChainID: 54321, + TeleporterContractAddress: teleporterContractAddress, + TeleporterDeployedBytecode: teleporterDeployedBytecode, + TeleporterDeployerAddress: teleporterDeployerAddress, + NodeCount: 2, + }, + }, + 2, + ) + log.Info("Started local network") +}) + +var _ = ginkgo.AfterSuite(func() { + LocalNetworkInstance.TearDownNetwork() +}) + +var _ = ginkgo.Describe("[Governance integration tests]", func() { + // Governance tests + ginkgo.It("Deliver ValidatorSetSig signed message", + ginkgo.Label(validatorSetSigLabel), + func() { + governanceFlows.ValidatorSetSig(LocalNetworkInstance) + }) +}) diff --git a/tests/local/network.go b/tests/local/network.go index f97770193..a8a574c63 100644 --- a/tests/local/network.go +++ b/tests/local/network.go @@ -20,18 +20,14 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/vms/platformvm" - avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/secp256k1fx" pwallet "github.com/ava-labs/avalanchego/wallet/chain/p/wallet" "github.com/ava-labs/avalanchego/wallet/subnet/primary" "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/ethclient" - subnetEvmInterfaces "github.com/ava-labs/subnet-evm/interfaces" - "github.com/ava-labs/subnet-evm/precompile/contracts/warp" "github.com/ava-labs/subnet-evm/rpc" subnetEvmTestUtils "github.com/ava-labs/subnet-evm/tests/utils" - warpBackend "github.com/ava-labs/subnet-evm/warp" teleportermessenger "github.com/ava-labs/teleporter/abi-bindings/go/teleporter/TeleporterMessenger" teleporterregistry "github.com/ava-labs/teleporter/abi-bindings/go/teleporter/registry/TeleporterRegistry" "github.com/ava-labs/teleporter/tests/interfaces" @@ -74,6 +70,7 @@ type SubnetSpec struct { NodeCount int } +// TODO: Decouple Teleporter from the network interface func NewLocalNetwork( ctx context.Context, name string, @@ -97,15 +94,6 @@ func NewLocalNetwork( globalFundedECDSAKey := globalFundedKey.ToECDSA() Expect(err).Should(BeNil()) - g, err := crypto.HexToECDSA(fundedKeyStr) - Expect(err).Should(BeNil()) - // TODONOW: remove these once txs are verified - Expect(g.PublicKey.X).Should(Equal(globalFundedECDSAKey.PublicKey.X)) - Expect(g.PublicKey.Y).Should(Equal(globalFundedECDSAKey.PublicKey.Y)) - Expect(g.X).Should(Equal(globalFundedECDSAKey.X)) - Expect(g.Y).Should(Equal(globalFundedECDSAKey.Y)) - Expect(g.D).Should(Equal(globalFundedECDSAKey.D)) - var subnets []*tmpnet.Subnet for _, subnetSpec := range subnetSpecs { nodes := subnetEvmTestUtils.NewTmpnetNodes(subnetSpec.NodeCount) @@ -163,10 +151,9 @@ func NewLocalNetwork( // Issue transactions to activate the proposerVM fork on the chains for _, subnet := range network.Subnets { - setupProposerVM(ctx, globalFundedECDSAKey, network, subnet.SubnetID) + utils.SetupProposerVM(ctx, globalFundedECDSAKey, network, subnet.SubnetID) } - // TODONOW: add Wallet LocalNetwork struct localNetwork := &LocalNetwork{ primaryNetworkInfo: &interfaces.SubnetTestInfo{}, subnetsInfo: make(map[ids.ID]*interfaces.SubnetTestInfo), @@ -195,6 +182,7 @@ func NewLocalNetwork( Expect(err).Should(BeNil()) localNetwork.pChainWallet = wallet.P() + // TODO: Convert all subnets to permissionless validation return localNetwork } @@ -365,6 +353,20 @@ func (n *LocalNetwork) DeployTeleporterContractToAllChains( log.Info("Deployed Teleporter contracts to C-Chain and all subnets") } +func (n *LocalNetwork) InitializeBlockchainIDOnAllChains( + fundedKey *ecdsa.PrivateKey, +) { + log.Info("Initializing blockchainID on C-Chain and all subnets") + ctx := context.Background() + for _, subnetInfo := range n.GetAllSubnetsInfo() { + opts, err := bind.NewKeyedTransactorWithChainID(fundedKey, subnetInfo.EVMChainID) + Expect(err).Should(BeNil()) + tx, err := subnetInfo.TeleporterMessenger.InitializeBlockchainID(opts) + Expect(err).Should(BeNil()) + utils.WaitForTransactionSuccess(ctx, subnetInfo, tx.Hash()) + } +} + func (n *LocalNetwork) DeployTeleporterRegistryContracts( teleporterAddress common.Address, deployerKey *ecdsa.PrivateKey, @@ -474,7 +476,7 @@ func (n *LocalNetwork) RelayMessage(ctx context.Context, sendEvent, err := utils.GetEventFromLogs(sourceReceipt.Logs, source.TeleporterMessenger.ParseSendCrossChainMessage) Expect(err).Should(BeNil()) - signedWarpMessage := n.ConstructSignedWarpMessage(ctx, sourceReceipt, source, destination) + signedWarpMessage := utils.ConstructSignedWarpMessage(ctx, sourceReceipt, source, destination) // Construct the transaction to send the Warp message to the destination chain signedTx := utils.CreateReceiveCrossChainMessageTransaction( @@ -569,22 +571,18 @@ func (n *LocalNetwork) AddSubnetValidators(ctx context.Context, subnetID ids.ID, n.setAllSubnetValues() } -// GetAllNodeIDs returns a slice that copies the NodeID's of all nodes in the network -func (n *LocalNetwork) GetAllNodeIDs() []ids.NodeID { - nodeIDs := make([]ids.NodeID, len(n.tmpnet.Nodes)) - for i, node := range n.tmpnet.Nodes { - nodeIDs[i] = node.NodeID - } - return nodeIDs -} - +// Restarts the nodes with the given nodeIDs. If nodeIDs is empty, restarts all nodes. func (n *LocalNetwork) RestartNodes(ctx context.Context, nodeIDs []ids.NodeID) { log.Info("Restarting nodes", "nodeIDs", nodeIDs) var nodes []*tmpnet.Node - for _, nodeID := range nodeIDs { - for _, node := range n.tmpnet.Nodes { - if node.NodeID == nodeID { - nodes = append(nodes, node) + if len(nodeIDs) == 0 { + nodes = n.tmpnet.Nodes + } else { + for _, nodeID := range nodeIDs { + for _, node := range n.tmpnet.Nodes { + if node.NodeID == nodeID { + nodes = append(nodes, node) + } } } } @@ -649,84 +647,6 @@ func (n *LocalNetwork) SetChainConfigs(chainConfigs map[string]string) { } } -func (n *LocalNetwork) ExtractWarpMessageFromLog( - ctx context.Context, - sourceReceipt *types.Receipt, - source interfaces.SubnetTestInfo, -) *avalancheWarp.UnsignedMessage { - log.Info("Fetching relevant warp logs from the newly produced block") - logs, err := source.RPCClient.FilterLogs(ctx, subnetEvmInterfaces.FilterQuery{ - BlockHash: &sourceReceipt.BlockHash, - Addresses: []common.Address{warp.Module.Address}, - }) - Expect(err).Should(BeNil()) - Expect(len(logs)).Should(Equal(1)) - - // Check for relevant warp log from subscription and ensure that it matches - // the log extracted from the last block. - txLog := logs[0] - log.Info("Parsing logData as unsigned warp message") - unsignedMsg, err := warp.UnpackSendWarpEventDataToMessage(txLog.Data) - Expect(err).Should(BeNil()) - return unsignedMsg -} - -func (n *LocalNetwork) ConstructSignedWarpMessage( - ctx context.Context, - sourceReceipt *types.Receipt, - source interfaces.SubnetTestInfo, - destination interfaces.SubnetTestInfo, -) *avalancheWarp.Message { - unsignedMsg := n.ExtractWarpMessageFromLog(ctx, sourceReceipt, source) - - // Set local variables for the duration of the test - unsignedWarpMessageID := unsignedMsg.ID() - log.Info( - "Parsed unsignedWarpMsg", - "unsignedWarpMessageID", unsignedWarpMessageID, - "unsignedWarpMessage", unsignedMsg, - ) - - // Loop over each client on source chain to ensure they all have time to accept the block. - // Note: if we did not confirm this here, the next stage could be racy since it assumes every node - // has accepted the block. - waitForAllValidatorsToAcceptBlock(ctx, source.NodeURIs, source.BlockchainID, sourceReceipt.BlockNumber.Uint64()) - - // Get the aggregate signature for the Warp message - log.Info("Fetching aggregate signature from the source chain validators") - return n.GetSignedMessage(ctx, source, destination, unsignedWarpMessageID) -} - -func (n *LocalNetwork) GetSignedMessage( - ctx context.Context, - source interfaces.SubnetTestInfo, - destination interfaces.SubnetTestInfo, - unsignedWarpMessageID ids.ID, -) *avalancheWarp.Message { - Expect(len(source.NodeURIs)).Should(BeNumerically(">", 0)) - warpClient, err := warpBackend.NewClient(source.NodeURIs[0], source.BlockchainID.String()) - Expect(err).Should(BeNil()) - - signingSubnetID := source.SubnetID - if source.SubnetID == constants.PrimaryNetworkID { - signingSubnetID = destination.SubnetID - } - - // Get the aggregate signature for the Warp message - signedWarpMessageBytes, err := warpClient.GetMessageAggregateSignature( - ctx, - unsignedWarpMessageID, - warp.WarpDefaultQuorumNumerator, - signingSubnetID.String(), - ) - Expect(err).Should(BeNil()) - - signedWarpMsg, err := avalancheWarp.ParseMessage(signedWarpMessageBytes) - Expect(err).Should(BeNil()) - - return signedWarpMsg -} - func (n *LocalNetwork) GetNetworkID() uint32 { return n.tmpnet.Genesis.NetworkID } diff --git a/tests/local/network_utils.go b/tests/local/network_utils.go deleted file mode 100644 index da166a6e0..000000000 --- a/tests/local/network_utils.go +++ /dev/null @@ -1,62 +0,0 @@ -package local - -import ( - "context" - "crypto/ecdsa" - "slices" - "time" - - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" - "github.com/ava-labs/subnet-evm/ethclient" - subnetEvmUtils "github.com/ava-labs/subnet-evm/tests/utils" - "github.com/ava-labs/teleporter/tests/utils" - "github.com/ethereum/go-ethereum/log" - - . "github.com/onsi/gomega" -) - -// Issues txs to activate the proposer VM fork on the specified subnet index in the manager -func setupProposerVM(ctx context.Context, fundedKey *ecdsa.PrivateKey, network *tmpnet.Network, subnetID ids.ID) { - subnetDetails := network.Subnets[slices.IndexFunc( - network.Subnets, - func(s *tmpnet.Subnet) bool { return s.SubnetID == subnetID }, - )] - - chainID := subnetDetails.Chains[0].ChainID - - nodeURI, err := network.GetURIForNodeID(subnetDetails.ValidatorIDs[0]) - Expect(err).Should(BeNil()) - uri := utils.HttpToWebsocketURI(nodeURI, chainID.String()) - - client, err := ethclient.Dial(uri) - Expect(err).Should(BeNil()) - chainIDInt, err := client.ChainID(ctx) - Expect(err).Should(BeNil()) - - err = subnetEvmUtils.IssueTxsToActivateProposerVMFork(ctx, chainIDInt, fundedKey, client) - Expect(err).Should(BeNil()) -} - -// Blocks until all validators specified in nodeURIs have reached the specified block height -func waitForAllValidatorsToAcceptBlock(ctx context.Context, nodeURIs []string, blockchainID ids.ID, height uint64) { - cctx, cancel := context.WithTimeout(ctx, 10*time.Second) - defer cancel() - for i, uri := range nodeURIs { - chainAWSURI := utils.HttpToWebsocketURI(uri, blockchainID.String()) - log.Debug("Creating ethclient for blockchain", "blockchainID", blockchainID.String(), "wsURI", chainAWSURI) - client, err := ethclient.Dial(chainAWSURI) - Expect(err).Should(BeNil()) - defer client.Close() - - // Loop until each node has advanced to >= the height of the block that emitted the warp log - for { - block, err := client.BlockByNumber(cctx, nil) - Expect(err).Should(BeNil()) - if block.NumberU64() >= height { - log.Debug("Client accepted the block containing SendWarpMessage", "client", i, "height", block.NumberU64()) - break - } - } - } -} diff --git a/tests/local/teleporter/teleporter_suite_test.go b/tests/local/teleporter/teleporter_suite_test.go new file mode 100644 index 000000000..34d646f6b --- /dev/null +++ b/tests/local/teleporter/teleporter_suite_test.go @@ -0,0 +1,188 @@ +package teleporter_test + +import ( + "context" + "os" + "testing" + "time" + + teleporterFlows "github.com/ava-labs/teleporter/tests/flows/teleporter" + registryFlows "github.com/ava-labs/teleporter/tests/flows/teleporter/registry" + "github.com/ava-labs/teleporter/tests/local" + deploymentUtils "github.com/ava-labs/teleporter/utils/deployment-utils" + "github.com/ethereum/go-ethereum/log" + "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +const ( + teleporterByteCodeFile = "./out/TeleporterMessenger.sol/TeleporterMessenger.json" + warpGenesisTemplateFile = "./tests/utils/warp-genesis-template.json" + + teleporterMessengerLabel = "TeleporterMessenger" + upgradabilityLabel = "upgradability" + utilsLabel = "utils" + validatorSetSigLabel = "ValidatorSetSig" + validatorManagerLabel = "ValidatorManager" +) + +var ( + LocalNetworkInstance *local.LocalNetwork +) + +func TestTeleporter(t *testing.T) { + if os.Getenv("RUN_E2E") == "" { + t.Skip("Environment variable RUN_E2E not set; skipping E2E tests") + } + + RegisterFailHandler(ginkgo.Fail) + ginkgo.RunSpecs(t, "Teleporter e2e test") +} + +// Define the Teleporter before and after suite functions. +var _ = ginkgo.BeforeSuite(func() { + // Generate the Teleporter deployment values + teleporterDeployerTransaction, teleporterDeployedBytecode, teleporterDeployerAddress, teleporterContractAddress, err := + deploymentUtils.ConstructKeylessTransaction( + teleporterByteCodeFile, + false, + deploymentUtils.GetDefaultContractCreationGasPrice(), + ) + Expect(err).Should(BeNil()) + + // Create the local network instance + ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) + defer cancel() + LocalNetworkInstance = local.NewLocalNetwork( + ctx, + "teleporter-test-local-network", + warpGenesisTemplateFile, + []local.SubnetSpec{ + { + Name: "A", + EVMChainID: 12345, + TeleporterContractAddress: teleporterContractAddress, + TeleporterDeployedBytecode: teleporterDeployedBytecode, + TeleporterDeployerAddress: teleporterDeployerAddress, + NodeCount: 2, + }, + { + Name: "B", + EVMChainID: 54321, + TeleporterContractAddress: teleporterContractAddress, + TeleporterDeployedBytecode: teleporterDeployedBytecode, + TeleporterDeployerAddress: teleporterDeployerAddress, + NodeCount: 2, + }, + }, + 2, + ) + log.Info("Started local network") + + // Only need to deploy Teleporter on the C-Chain since it is included in the genesis of the subnet chains. + _, fundedKey := LocalNetworkInstance.GetFundedAccountInfo() + LocalNetworkInstance.DeployTeleporterContractToCChain( + teleporterDeployerTransaction, + teleporterDeployerAddress, + teleporterContractAddress, + fundedKey, + ) + LocalNetworkInstance.SetTeleporterContractAddress(teleporterContractAddress) + LocalNetworkInstance.InitializeBlockchainIDOnAllChains(fundedKey) + + // Deploy the Teleporter registry contracts to all subnets and the C-Chain. + LocalNetworkInstance.DeployTeleporterRegistryContracts(teleporterContractAddress, fundedKey) + + log.Info("Set up ginkgo before suite") +}) + +var _ = ginkgo.AfterSuite(func() { + LocalNetworkInstance.TearDownNetwork() + LocalNetworkInstance = nil +}) + +var _ = ginkgo.Describe("[Teleporter integration tests]", func() { + // Teleporter tests + ginkgo.It("Send a message from Subnet A to Subnet B, and one from B to A", + ginkgo.Label(teleporterMessengerLabel), + func() { + teleporterFlows.BasicSendReceive(LocalNetworkInstance) + }) + ginkgo.It("Deliver to the wrong chain", + ginkgo.Label(teleporterMessengerLabel), + func() { + teleporterFlows.DeliverToWrongChain(LocalNetworkInstance) + }) + ginkgo.It("Deliver to non-existent contract", + ginkgo.Label(teleporterMessengerLabel), + func() { + teleporterFlows.DeliverToNonExistentContract(LocalNetworkInstance) + }) + ginkgo.It("Retry successful execution", + ginkgo.Label(teleporterMessengerLabel), + func() { + teleporterFlows.RetrySuccessfulExecution(LocalNetworkInstance) + }) + ginkgo.It("Unallowed relayer", + ginkgo.Label(teleporterMessengerLabel), + func() { + teleporterFlows.UnallowedRelayer(LocalNetworkInstance) + }) + ginkgo.It("Relay message twice", + ginkgo.Label(teleporterMessengerLabel), + func() { + teleporterFlows.RelayMessageTwice(LocalNetworkInstance) + }) + ginkgo.It("Add additional fee amount", + ginkgo.Label(teleporterMessengerLabel), + func() { + teleporterFlows.AddFeeAmount(LocalNetworkInstance) + }) + ginkgo.It("Send specific receipts", + ginkgo.Label(teleporterMessengerLabel), + func() { + teleporterFlows.SendSpecificReceipts(LocalNetworkInstance) + }) + ginkgo.It("Insufficient gas", + ginkgo.Label(teleporterMessengerLabel), + func() { + teleporterFlows.InsufficientGas(LocalNetworkInstance) + }) + ginkgo.It("Resubmit altered message", + ginkgo.Label(teleporterMessengerLabel), + func() { + teleporterFlows.ResubmitAlteredMessage(LocalNetworkInstance) + }) + ginkgo.It("Calculate Teleporter message IDs", + ginkgo.Label(utilsLabel), + func() { + teleporterFlows.CalculateMessageID(LocalNetworkInstance) + }) + ginkgo.It("Relayer modifies message", + ginkgo.Label(teleporterMessengerLabel), + func() { + teleporterFlows.RelayerModifiesMessage(LocalNetworkInstance) + }) + ginkgo.It("Validator churn", + ginkgo.Label(teleporterMessengerLabel), + func() { + teleporterFlows.ValidatorChurn(LocalNetworkInstance) + }) + + // Teleporter Registry tests + ginkgo.It("Teleporter registry", + ginkgo.Label(upgradabilityLabel), + func() { + registryFlows.TeleporterRegistry(LocalNetworkInstance) + }) + ginkgo.It("Check upgrade access", + ginkgo.Label(upgradabilityLabel), + func() { + registryFlows.CheckUpgradeAccess(LocalNetworkInstance) + }) + ginkgo.It("Pause and Unpause Teleporter", + ginkgo.Label(upgradabilityLabel), + func() { + registryFlows.PauseTeleporter(LocalNetworkInstance) + }) +}) diff --git a/tests/local/validator-manager/validator_manager_suite_test.go b/tests/local/validator-manager/validator_manager_suite_test.go new file mode 100644 index 000000000..25d780c21 --- /dev/null +++ b/tests/local/validator-manager/validator_manager_suite_test.go @@ -0,0 +1,120 @@ +package validator_manager_test + +import ( + "context" + "os" + "testing" + "time" + + validatorManagerFlows "github.com/ava-labs/teleporter/tests/flows/validator-manager" + "github.com/ava-labs/teleporter/tests/local" + deploymentUtils "github.com/ava-labs/teleporter/utils/deployment-utils" + "github.com/ethereum/go-ethereum/log" + "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +const ( + teleporterByteCodeFile = "./out/TeleporterMessenger.sol/TeleporterMessenger.json" + warpGenesisTemplateFile = "./tests/utils/warp-genesis-template.json" + + teleporterMessengerLabel = "TeleporterMessenger" + upgradabilityLabel = "upgradability" + utilsLabel = "utils" + validatorSetSigLabel = "ValidatorSetSig" + validatorManagerLabel = "ValidatorManager" +) + +var ( + LocalNetworkInstance *local.LocalNetwork +) + +func TestValidatorManager(t *testing.T) { + if os.Getenv("RUN_E2E") == "" { + t.Skip("Environment variable RUN_E2E not set; skipping E2E tests") + } + + RegisterFailHandler(ginkgo.Fail) + ginkgo.RunSpecs(t, "Teleporter e2e test") +} + +// Define the Teleporter before and after suite functions. +var _ = ginkgo.BeforeEach(func() { + // Generate the Teleporter deployment values + teleporterDeployerTransaction, teleporterDeployedBytecode, teleporterDeployerAddress, teleporterContractAddress, err := + deploymentUtils.ConstructKeylessTransaction( + teleporterByteCodeFile, + false, + deploymentUtils.GetDefaultContractCreationGasPrice(), + ) + Expect(err).Should(BeNil()) + + // Create the local network instance + ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) + defer cancel() + LocalNetworkInstance = local.NewLocalNetwork( + ctx, + "teleporter-test-local-network", + warpGenesisTemplateFile, + []local.SubnetSpec{ + { + Name: "A", + EVMChainID: 12345, + TeleporterContractAddress: teleporterContractAddress, + TeleporterDeployedBytecode: teleporterDeployedBytecode, + TeleporterDeployerAddress: teleporterDeployerAddress, + NodeCount: 2, + }, + { + Name: "B", + EVMChainID: 54321, + TeleporterContractAddress: teleporterContractAddress, + TeleporterDeployedBytecode: teleporterDeployedBytecode, + TeleporterDeployerAddress: teleporterDeployerAddress, + NodeCount: 2, + }, + }, + 2, + ) + log.Info("Started local network") + + // Only need to deploy Teleporter on the C-Chain since it is included in the genesis of the subnet chains. + _, fundedKey := LocalNetworkInstance.GetFundedAccountInfo() + LocalNetworkInstance.DeployTeleporterContractToCChain( + teleporterDeployerTransaction, + teleporterDeployerAddress, + teleporterContractAddress, + fundedKey, + ) + LocalNetworkInstance.SetTeleporterContractAddress(teleporterContractAddress) + LocalNetworkInstance.InitializeBlockchainIDOnAllChains(fundedKey) + + // Deploy the Teleporter registry contracts to all subnets and the C-Chain. + LocalNetworkInstance.DeployTeleporterRegistryContracts(teleporterContractAddress, fundedKey) + + log.Info("Set up ginkgo before suite") +}) + +var _ = ginkgo.AfterEach(func() { + LocalNetworkInstance.TearDownNetwork() + LocalNetworkInstance = nil +}) + +var _ = ginkgo.Describe("[Validator manager integration tests]", func() { + // Validator Manager tests + ginkgo.It("Native token staking manager", + ginkgo.Label(validatorManagerLabel), + func() { + validatorManagerFlows.NativeTokenStakingManager(LocalNetworkInstance) + }) + ginkgo.It("ERC20 token staking manager", + ginkgo.Label(validatorManagerLabel), + func() { + validatorManagerFlows.ERC20TokenStakingManager(LocalNetworkInstance) + }) + ginkgo.It("PoA migration to PoS", + ginkgo.Label(validatorManagerLabel), + func() { + validatorManagerFlows.PoAMigrationToPoS(LocalNetworkInstance) + }) +}) diff --git a/tests/utils/chain.go b/tests/utils/chain.go index 5469d8f10..27778d27b 100644 --- a/tests/utils/chain.go +++ b/tests/utils/chain.go @@ -6,8 +6,10 @@ import ( "encoding/json" "errors" "fmt" + goLog "log" "math/big" "os" + "slices" "strconv" "strings" "time" @@ -32,6 +34,9 @@ import ( "github.com/ava-labs/subnet-evm/ethclient" subnetEvmInterfaces "github.com/ava-labs/subnet-evm/interfaces" "github.com/ava-labs/subnet-evm/precompile/contracts/nativeminter" + "github.com/ava-labs/subnet-evm/precompile/contracts/warp" + subnetEvmUtils "github.com/ava-labs/subnet-evm/tests/utils" + warpBackend "github.com/ava-labs/subnet-evm/warp" nativeMinter "github.com/ava-labs/teleporter/abi-bindings/go/INativeMinter" "github.com/ava-labs/teleporter/tests/interfaces" gasUtils "github.com/ava-labs/teleporter/utils/gas-utils" @@ -75,6 +80,7 @@ var WarpEnabledChainConfig = tmpnet.FlagsMap{ type Node struct { NodeID ids.NodeID NodePoP *signer.ProofOfPossession + Weight uint64 } // @@ -214,7 +220,7 @@ func waitForTransaction( txHash common.Hash, success bool, ) *types.Receipt { - cctx, cancel := context.WithTimeout(ctx, 10*time.Second) + cctx, cancel := context.WithTimeout(ctx, 20*time.Second) defer cancel() receipt, err := WaitMined(cctx, subnetInfo.RPCClient, txHash) @@ -317,13 +323,13 @@ func TraceTransaction(ctx context.Context, rpcClient ethclient.Client, txHash co // Takes a tx hash instead of the full tx in the subnet-evm version of this function. // Copied and modified from https://github.com/ava-labs/subnet-evm/blob/v0.6.0-fuji/accounts/abi/bind/util.go#L42 func WaitMined(ctx context.Context, rpcClient ethclient.Client, txHash common.Hash) (*types.Receipt, error) { - cctx, cancel := context.WithTimeout(ctx, 20*time.Second) - defer cancel() - - receipt, err := waitForTransactionReceipt(cctx, rpcClient, txHash) + now := time.Now() + receipt, err := waitForTransactionReceipt(ctx, rpcClient, txHash) if err != nil { return nil, err } + since := time.Since(now) + goLog.Println("Transaction mined", "txHash", txHash.Hex(), "duration", since) // Check that the block height endpoint returns a block height as high as the block number that the transaction was // included in. This is to workaround the issue where multiple nodes behind a public RPC endpoint see @@ -332,7 +338,7 @@ func WaitMined(ctx context.Context, rpcClient ethclient.Client, txHash common.Ha // configured to return the lowest value currently returned by any node behind the load balancer, so waiting for // it to be at least as high as the block height specified in the receipt should provide a relatively strong // indication that the transaction has been seen widely throughout the network. - err = waitForBlockHeight(cctx, rpcClient, receipt.BlockNumber.Uint64()) + err = waitForBlockHeight(ctx, rpcClient, receipt.BlockNumber.Uint64()) if err != nil { return nil, err } @@ -539,7 +545,6 @@ func InstantiateGenesisTemplate( // func NewSignatureAggregator(apiUri string, subnets []ids.ID) *aggregator.SignatureAggregator { - logger := logging.NoLog{} cfg := sigAggConfig.Config{ PChainAPI: &relayerConfig.APIConfig{ BaseURL: apiUri, @@ -552,7 +557,7 @@ func NewSignatureAggregator(apiUri string, subnets []ids.ID) *aggregator.Signatu trackedSubnets.Add(subnets...) registry := prometheus.NewRegistry() appRequestNetwork, err := peers.NewNetwork( - logging.Debug, + logging.Info, registry, trackedSubnets, &cfg, @@ -560,7 +565,7 @@ func NewSignatureAggregator(apiUri string, subnets []ids.ID) *aggregator.Signatu Expect(err).Should(BeNil()) messageCreator, err := message.NewCreator( - logger, + logging.NoLog{}, registry, constants.DefaultNetworkCompressionType, constants.DefaultNetworkMaximumInboundTimeout, @@ -568,9 +573,9 @@ func NewSignatureAggregator(apiUri string, subnets []ids.ID) *aggregator.Signatu Expect(err).Should(BeNil()) agg, err := aggregator.NewSignatureAggregator( appRequestNetwork, - logger, + logging.NoLog{}, 1024, - metrics.NewSignatureAggregatorMetrics(prometheus.DefaultRegisterer), + metrics.NewSignatureAggregatorMetrics(prometheus.NewRegistry()), messageCreator, // Setting the etnaTime to a minute ago so that the post-etna code path is used in the test time.Now().Add(-1*time.Minute), @@ -579,6 +584,10 @@ func NewSignatureAggregator(apiUri string, subnets []ids.ID) *aggregator.Signatu return agg } +// +// Native minter utils +// + // Funded key must have admin access to set new admin. func AddNativeMinterAdmin( ctx context.Context, @@ -595,3 +604,126 @@ func AddNativeMinterAdmin( Expect(err).Should(BeNil()) WaitForTransactionSuccess(ctx, subnet, tx.Hash()) } + +// Blocks until all validators specified in nodeURIs have reached the specified block height +func WaitForAllValidatorsToAcceptBlock(ctx context.Context, nodeURIs []string, blockchainID ids.ID, height uint64) { + cctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + for i, uri := range nodeURIs { + chainAWSURI := HttpToWebsocketURI(uri, blockchainID.String()) + log.Debug("Creating ethclient for blockchain", "blockchainID", blockchainID.String(), "wsURI", chainAWSURI) + client, err := ethclient.Dial(chainAWSURI) + Expect(err).Should(BeNil()) + defer client.Close() + + // Loop until each node has advanced to >= the height of the block that emitted the warp log + for { + block, err := client.BlockByNumber(cctx, nil) + Expect(err).Should(BeNil()) + if block.NumberU64() >= height { + log.Debug("Client accepted the block containing SendWarpMessage", "client", i, "height", block.NumberU64()) + break + } + } + } +} + +func ExtractWarpMessageFromLog( + ctx context.Context, + sourceReceipt *types.Receipt, + source interfaces.SubnetTestInfo, +) *avalancheWarp.UnsignedMessage { + log.Info("Fetching relevant warp logs from the newly produced block") + logs, err := source.RPCClient.FilterLogs(ctx, subnetEvmInterfaces.FilterQuery{ + BlockHash: &sourceReceipt.BlockHash, + Addresses: []common.Address{warp.Module.Address}, + }) + Expect(err).Should(BeNil()) + Expect(len(logs)).Should(Equal(1)) + + // Check for relevant warp log from subscription and ensure that it matches + // the log extracted from the last block. + txLog := logs[0] + log.Info("Parsing logData as unsigned warp message") + unsignedMsg, err := warp.UnpackSendWarpEventDataToMessage(txLog.Data) + Expect(err).Should(BeNil()) + return unsignedMsg +} + +func ConstructSignedWarpMessage( + ctx context.Context, + sourceReceipt *types.Receipt, + source interfaces.SubnetTestInfo, + destination interfaces.SubnetTestInfo, +) *avalancheWarp.Message { + unsignedMsg := ExtractWarpMessageFromLog(ctx, sourceReceipt, source) + + // Set local variables for the duration of the test + unsignedWarpMessageID := unsignedMsg.ID() + log.Info( + "Parsed unsignedWarpMsg", + "unsignedWarpMessageID", unsignedWarpMessageID, + "unsignedWarpMessage", unsignedMsg, + ) + + // Loop over each client on source chain to ensure they all have time to accept the block. + // Note: if we did not confirm this here, the next stage could be racy since it assumes every node + // has accepted the block. + WaitForAllValidatorsToAcceptBlock(ctx, source.NodeURIs, source.BlockchainID, sourceReceipt.BlockNumber.Uint64()) + + // Get the aggregate signature for the Warp message + log.Info("Fetching aggregate signature from the source chain validators") + return GetSignedMessage(ctx, source, destination, unsignedWarpMessageID) +} + +func GetSignedMessage( + ctx context.Context, + source interfaces.SubnetTestInfo, + destination interfaces.SubnetTestInfo, + unsignedWarpMessageID ids.ID, +) *avalancheWarp.Message { + Expect(len(source.NodeURIs)).Should(BeNumerically(">", 0)) + warpClient, err := warpBackend.NewClient(source.NodeURIs[0], source.BlockchainID.String()) + Expect(err).Should(BeNil()) + + signingSubnetID := source.SubnetID + if source.SubnetID == constants.PrimaryNetworkID { + signingSubnetID = destination.SubnetID + } + + // Get the aggregate signature for the Warp message + // TODO: use signature aggregator + signedWarpMessageBytes, err := warpClient.GetMessageAggregateSignature( + ctx, + unsignedWarpMessageID, + warp.WarpDefaultQuorumNumerator, + signingSubnetID.String(), + ) + Expect(err).Should(BeNil()) + + signedWarpMsg, err := avalancheWarp.ParseMessage(signedWarpMessageBytes) + Expect(err).Should(BeNil()) + + return signedWarpMsg +} + +func SetupProposerVM(ctx context.Context, fundedKey *ecdsa.PrivateKey, network *tmpnet.Network, subnetID ids.ID) { + subnetDetails := network.Subnets[slices.IndexFunc( + network.Subnets, + func(s *tmpnet.Subnet) bool { return s.SubnetID == subnetID }, + )] + + chainID := subnetDetails.Chains[0].ChainID + + nodeURI, err := network.GetURIForNodeID(subnetDetails.ValidatorIDs[0]) + Expect(err).Should(BeNil()) + uri := HttpToWebsocketURI(nodeURI, chainID.String()) + + client, err := ethclient.Dial(uri) + Expect(err).Should(BeNil()) + chainIDInt, err := client.ChainID(ctx) + Expect(err).Should(BeNil()) + + err = subnetEvmUtils.IssueTxsToActivateProposerVMFork(ctx, chainIDInt, fundedKey, client) + Expect(err).Should(BeNil()) +} diff --git a/tests/utils/governance.go b/tests/utils/governance.go index 177d3f017..96d03555d 100644 --- a/tests/utils/governance.go +++ b/tests/utils/governance.go @@ -48,7 +48,7 @@ func ExecuteValidatorSetSigCallAndVerify( unsignedMessage *avalancheWarp.UnsignedMessage, expectSuccess bool, ) *types.Receipt { - signedWarpMsg := network.GetSignedMessage(ctx, source, destination, unsignedMessage.ID()) + signedWarpMsg := GetSignedMessage(ctx, source, destination, unsignedMessage.ID()) log.Info("Got signed warp message", "messageID", signedWarpMsg.ID()) signedPredicateTx := CreateExecuteCallPredicateTransaction( diff --git a/tests/utils/teleporter.go b/tests/utils/teleporter.go index 1647bd0fa..7f9840824 100644 --- a/tests/utils/teleporter.go +++ b/tests/utils/teleporter.go @@ -250,7 +250,7 @@ func AddProtocolVersionAndWaitForAcceptance( senderKey *ecdsa.PrivateKey, unsignedMessage *avalancheWarp.UnsignedMessage, ) { - signedWarpMsg := network.GetSignedMessage(ctx, subnet, subnet, unsignedMessage.ID()) + signedWarpMsg := GetSignedMessage(ctx, subnet, subnet, unsignedMessage.ID()) log.Info("Got signed warp message", "messageID", signedWarpMsg.ID()) // Construct tx to add protocol version and send to destination chain diff --git a/tests/utils/validator_manager.go b/tests/utils/validator_manager.go index 867fca929..b856d8aa8 100644 --- a/tests/utils/validator_manager.go +++ b/tests/utils/validator_manager.go @@ -9,16 +9,20 @@ import ( "log" "math/big" "reflect" + "sort" "time" + "github.com/ava-labs/avalanchego/api/info" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/proto/pb/platformvm" "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/formatting/address" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" + "github.com/ava-labs/avalanchego/vms/platformvm/txs" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" - warpMessages "github.com/ava-labs/avalanchego/vms/platformvm/warp/message" + warpMessage "github.com/ava-labs/avalanchego/vms/platformvm/warp/message" warpPayload "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" "github.com/ava-labs/avalanchego/vms/secp256k1fx" "github.com/ava-labs/awm-relayer/signature-aggregator/aggregator" @@ -26,6 +30,7 @@ import ( "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/precompile/contracts/warp" predicateutils "github.com/ava-labs/subnet-evm/predicate" + subnetEvmUtils "github.com/ava-labs/subnet-evm/tests/utils" exampleerc20 "github.com/ava-labs/teleporter/abi-bindings/go/mocks/ExampleERC20" erc20tokenstakingmanager "github.com/ava-labs/teleporter/abi-bindings/go/validator-manager/ERC20TokenStakingManager" examplerewardcalculator "github.com/ava-labs/teleporter/abi-bindings/go/validator-manager/ExampleRewardCalculator" @@ -33,6 +38,7 @@ import ( poavalidatormanager "github.com/ava-labs/teleporter/abi-bindings/go/validator-manager/PoAValidatorManager" "github.com/ava-labs/teleporter/tests/interfaces" "github.com/ethereum/go-ethereum/common" + "google.golang.org/protobuf/proto" . "github.com/onsi/gomega" ) @@ -45,6 +51,7 @@ const ( DefaultMaxStakeMultiplier uint8 = 4 DefaultMaxChurnPercentage uint8 = 20 DefaultChurnPeriodSeconds uint64 = 1 + DefaultPChainAddress string = "P-local18jma8ppw3nhx5r4ap8clazz0dps7rv5u00z96u" ) // @@ -264,25 +271,37 @@ func InitializeNativeTokenValidatorSet( validatorManagerAddress common.Address, network interfaces.LocalNetwork, signatureAggregator *aggregator.SignatureAggregator, - initialValidatorWeight uint64, -) ids.ID { - nodeID := ids.GenerateTestID() - blsPublicKey := [bls.PublicKeyLen]byte{} - subnetConversionData := nativetokenstakingmanager.SubnetConversionData{ + nodes []Node, +) []ids.ID { + initialValidators := make([]warpMessage.SubnetConversionValidatorData, len(nodes)) + initialValidatorsABI := make([]nativetokenstakingmanager.InitialValidator, len(nodes)) + for i, node := range nodes { + initialValidators[i] = warpMessage.SubnetConversionValidatorData{ + NodeID: node.NodeID.Bytes(), + BLSPublicKey: node.NodePoP.PublicKey, + Weight: nodes[i].Weight, + } + initialValidatorsABI[i] = nativetokenstakingmanager.InitialValidator{ + NodeID: node.NodeID.Bytes(), + BlsPublicKey: node.NodePoP.PublicKey[:], + Weight: nodes[i].Weight, + } + } + + subnetConversionData := warpMessage.SubnetConversionData{ + SubnetID: subnetInfo.SubnetID, + ManagerChainID: subnetInfo.BlockchainID, + ManagerAddress: validatorManagerAddress[:], + Validators: initialValidators, + } + subnetConversionDataABI := nativetokenstakingmanager.SubnetConversionData{ SubnetID: subnetInfo.SubnetID, ValidatorManagerBlockchainID: subnetInfo.BlockchainID, ValidatorManagerAddress: validatorManagerAddress, - InitialValidators: []nativetokenstakingmanager.InitialValidator{ - { - NodeID: nodeID[:], - Weight: initialValidatorWeight, - BlsPublicKey: blsPublicKey[:], - }, - }, + InitialValidators: initialValidatorsABI, } - subnetConversionDataBytes, err := PackSubnetConversionData(subnetConversionData) + subnetConversionID, err := warpMessage.SubnetConversionID(subnetConversionData) Expect(err).Should(BeNil()) - subnetConversionID := sha256.Sum256(subnetConversionDataBytes) subnetConversionSignedMessage := ConstructSubnetConversionMessage( subnetConversionID, subnetInfo, @@ -297,21 +316,24 @@ func InitializeNativeTokenValidatorSet( subnetInfo, validatorManagerAddress, subnetConversionSignedMessage, - subnetConversionData, + subnetConversionDataABI, ) initialValidatorCreatedEvent, err := GetEventFromLogs( receipt.Logs, validatorManager.ParseInitialValidatorCreated, ) Expect(err).Should(BeNil()) - Expect(initialValidatorCreatedEvent.NodeID).Should(Equal(subnetConversionData.InitialValidators[0].NodeID)) - Expect(initialValidatorCreatedEvent.Weight).Should(Equal(new(big.Int).SetUint64(initialValidatorWeight))) + var validationIDs []ids.ID + for i := range nodes { + validationIDs = append(validationIDs, subnetInfo.SubnetID.Append(uint32(i))) + } + + Expect(initialValidatorCreatedEvent.Weight).Should(Equal(new(big.Int).SetUint64(nodes[0].Weight))) - expectedValidationID := CalculateSubnetConversionValidationId(subnetInfo.SubnetID, 0) emittedValidationID := ids.ID(initialValidatorCreatedEvent.ValidationID) - Expect(emittedValidationID).Should(Equal(expectedValidationID)) + Expect(emittedValidationID).Should(Equal(validationIDs[0])) - return emittedValidationID + return validationIDs } func InitializeERC20TokenValidatorSet( @@ -324,25 +346,23 @@ func InitializeERC20TokenValidatorSet( network interfaces.LocalNetwork, signatureAggregator *aggregator.SignatureAggregator, nodes []Node, - initialValidatorWeights []uint64, ) []ids.ID { - Expect(len(nodes)).Should(Equal(len(initialValidatorWeights))) - initialValidators := make([]warpMessages.SubnetConversionValidatorData, len(nodes)) + initialValidators := make([]warpMessage.SubnetConversionValidatorData, len(nodes)) initialValidatorsABI := make([]erc20tokenstakingmanager.InitialValidator, len(nodes)) for i, node := range nodes { - initialValidators[i] = warpMessages.SubnetConversionValidatorData{ + initialValidators[i] = warpMessage.SubnetConversionValidatorData{ NodeID: node.NodeID.Bytes(), BLSPublicKey: node.NodePoP.PublicKey, - Weight: initialValidatorWeights[i], + Weight: nodes[i].Weight, } initialValidatorsABI[i] = erc20tokenstakingmanager.InitialValidator{ NodeID: node.NodeID.Bytes(), BlsPublicKey: node.NodePoP.PublicKey[:], - Weight: initialValidatorWeights[i], + Weight: nodes[i].Weight, } } - subnetConversionData := warpMessages.SubnetConversionData{ + subnetConversionData := warpMessage.SubnetConversionData{ SubnetID: subnetInfo.SubnetID, ManagerChainID: subnetInfo.BlockchainID, ManagerAddress: validatorManagerAddress[:], @@ -354,14 +374,8 @@ func InitializeERC20TokenValidatorSet( ValidatorManagerAddress: validatorManagerAddress, InitialValidators: initialValidatorsABI, } - subnetConversionID, err := warpMessages.SubnetConversionID(subnetConversionData) - log.Println("Reconstructed SubnetConversionID") - log.Println(subnetConversionData) - log.Printf("conversionID: %s\n", subnetConversionID.String()) - Expect(err).Should(BeNil()) - // subnetConversionDataBytes, err := PackSubnetConversionData(subnetConversionData) - // Expect(err).Should(BeNil()) - // subnetConversionID := sha256.Sum256(subnetConversionDataBytes) + subnetConversionID, err := warpMessage.SubnetConversionID(subnetConversionData) + Expect(err).Should(BeNil()) subnetConversionSignedMessage := ConstructSubnetConversionMessage( subnetConversionID, subnetInfo, @@ -369,10 +383,7 @@ func InitializeERC20TokenValidatorSet( network, signatureAggregator, ) - log.Println("SubnetConversionSignedMessage") - log.Println(subnetConversionSignedMessage.Signature.NumSigners()) - log.Println(subnetConversionSignedMessage.Signature.String()) - log.Println(subnetConversionSignedMessage.SourceChainID.String()) + // Deliver the Warp message to the subnet receipt := DeliverERC20TokenSubnetConversion( ctx, @@ -389,21 +400,14 @@ func InitializeERC20TokenValidatorSet( Expect(err).Should(BeNil()) var validationIDs []ids.ID for i := range nodes { - validationIDs = append(validationIDs, CalculateSubnetConversionValidationId(subnetInfo.SubnetID, uint32(i))) + validationIDs = append(validationIDs, subnetInfo.SubnetID.Append(uint32(i))) } - // TODONOW: Validate all nodes - // for i := range nodes { - // TODONOW: Fix this validation - // Expect(initialValidatorCreatedEvent.NodeID).Should(Equal(subnetConversionData.Validators[i].NodeID)) - Expect(initialValidatorCreatedEvent.Weight).Should(Equal(new(big.Int).SetUint64(initialValidatorWeights[0]))) + Expect(initialValidatorCreatedEvent.Weight).Should(Equal(new(big.Int).SetUint64(nodes[0].Weight))) emittedValidationID := ids.ID(initialValidatorCreatedEvent.ValidationID) Expect(emittedValidationID).Should(Equal(validationIDs[0])) - log.Println("Expected Validation ID", validationIDs[0]) - log.Println("Emitted Validation ID", emittedValidationID) - // } - log.Println("Validation IDs", validationIDs) + return validationIDs } @@ -416,26 +420,37 @@ func InitializePoAValidatorSet( validatorManagerAddress common.Address, network interfaces.LocalNetwork, signatureAggregator *aggregator.SignatureAggregator, - initialValidatorWeight uint64, -) ids.ID { - nodeID := ids.GenerateTestID() - blsPublicKey := [bls.PublicKeyLen]byte{} - subnetConversionData := poavalidatormanager.SubnetConversionData{ + nodes []Node, +) []ids.ID { + initialValidators := make([]warpMessage.SubnetConversionValidatorData, len(nodes)) + initialValidatorsABI := make([]poavalidatormanager.InitialValidator, len(nodes)) + for i, node := range nodes { + initialValidators[i] = warpMessage.SubnetConversionValidatorData{ + NodeID: node.NodeID.Bytes(), + BLSPublicKey: node.NodePoP.PublicKey, + Weight: nodes[i].Weight, + } + initialValidatorsABI[i] = poavalidatormanager.InitialValidator{ + NodeID: node.NodeID.Bytes(), + BlsPublicKey: node.NodePoP.PublicKey[:], + Weight: nodes[i].Weight, + } + } + + subnetConversionData := warpMessage.SubnetConversionData{ + SubnetID: subnetInfo.SubnetID, + ManagerChainID: subnetInfo.BlockchainID, + ManagerAddress: validatorManagerAddress[:], + Validators: initialValidators, + } + subnetConversionDataABI := poavalidatormanager.SubnetConversionData{ SubnetID: subnetInfo.SubnetID, ValidatorManagerBlockchainID: subnetInfo.BlockchainID, ValidatorManagerAddress: validatorManagerAddress, - InitialValidators: []poavalidatormanager.InitialValidator{ - { - NodeID: nodeID[:], - Weight: initialValidatorWeight, - BlsPublicKey: blsPublicKey[:], - }, - }, + InitialValidators: initialValidatorsABI, } - - subnetConversionDataBytes, err := PackSubnetConversionData(subnetConversionData) + subnetConversionID, err := warpMessage.SubnetConversionID(subnetConversionData) Expect(err).Should(BeNil()) - subnetConversionID := sha256.Sum256(subnetConversionDataBytes) subnetConversionSignedMessage := ConstructSubnetConversionMessage( subnetConversionID, subnetInfo, @@ -450,21 +465,24 @@ func InitializePoAValidatorSet( subnetInfo, validatorManagerAddress, subnetConversionSignedMessage, - subnetConversionData, + subnetConversionDataABI, ) initialValidatorCreatedEvent, err := GetEventFromLogs( receipt.Logs, validatorManager.ParseInitialValidatorCreated, ) Expect(err).Should(BeNil()) - Expect(initialValidatorCreatedEvent.NodeID).Should(Equal(subnetConversionData.InitialValidators[0].NodeID)) - Expect(initialValidatorCreatedEvent.Weight).Should(Equal(new(big.Int).SetUint64(initialValidatorWeight))) + var validationIDs []ids.ID + for i := range nodes { + validationIDs = append(validationIDs, subnetInfo.SubnetID.Append(uint32(i))) + } + + Expect(initialValidatorCreatedEvent.Weight).Should(Equal(new(big.Int).SetUint64(nodes[0].Weight))) - expectedValidationID := CalculateSubnetConversionValidationId(subnetInfo.SubnetID, 0) emittedValidationID := ids.ID(initialValidatorCreatedEvent.ValidationID) - Expect(emittedValidationID).Should(Equal(expectedValidationID)) + Expect(emittedValidationID).Should(Equal(validationIDs[0])) - return emittedValidationID + return validationIDs } func DeliverNativeTokenSubnetConversion( @@ -542,8 +560,8 @@ func InitializeNativeValidatorRegistration( senderKey *ecdsa.PrivateKey, subnet interfaces.SubnetTestInfo, stakeAmount *big.Int, - nodeID ids.ID, - blsPublicKey [bls.PublicKeyLen]byte, + node Node, + expiry uint64, stakingManager *nativetokenstakingmanager.NativeTokenStakingManager, ) (*types.Receipt, ids.ID) { opts, err := bind.NewKeyedTransactorWithChainID(senderKey, subnet.EVMChainID) @@ -553,9 +571,9 @@ func InitializeNativeValidatorRegistration( tx, err := stakingManager.InitializeValidatorRegistration( opts, nativetokenstakingmanager.ValidatorRegistrationInput{ - NodeID: nodeID[:], - RegistrationExpiry: uint64(time.Now().Add(24 * time.Hour).Unix()), - BlsPublicKey: blsPublicKey[:], + NodeID: node.NodeID[:], + RegistrationExpiry: expiry, + BlsPublicKey: node.NodePoP.PublicKey[:], }, DefaultMinDelegateFeeBips, DefaultMinStakeDurationSeconds, @@ -618,9 +636,8 @@ func InitializePoAValidatorRegistration( ctx context.Context, senderKey *ecdsa.PrivateKey, subnet interfaces.SubnetTestInfo, - weight uint64, - nodeID ids.ID, - blsPublicKey [bls.PublicKeyLen]byte, + node Node, + expiry uint64, validatorManager *poavalidatormanager.PoAValidatorManager, ) (*types.Receipt, ids.ID) { opts, err := bind.NewKeyedTransactorWithChainID(senderKey, subnet.EVMChainID) @@ -629,11 +646,11 @@ func InitializePoAValidatorRegistration( tx, err := validatorManager.InitializeValidatorRegistration( opts, poavalidatormanager.ValidatorRegistrationInput{ - NodeID: nodeID[:], - RegistrationExpiry: uint64(time.Now().Add(24 * time.Hour).Unix()), - BlsPublicKey: blsPublicKey[:], + NodeID: node.NodeID[:], + RegistrationExpiry: expiry, + BlsPublicKey: node.NodePoP.PublicKey[:], }, - weight, + node.Weight, ) Expect(err).Should(BeNil()) receipt := WaitForTransactionSuccess(ctx, subnet, tx.Hash()) @@ -744,45 +761,44 @@ func InitializeAndCompleteNativeValidatorRegistration( pChainInfo interfaces.SubnetTestInfo, stakingManager *nativetokenstakingmanager.NativeTokenStakingManager, stakingManagerContractAddress common.Address, - stakeAmount *big.Int, + expiry uint64, + node Node, ) ids.ID { + stakeAmount, err := stakingManager.WeightToValue( + &bind.CallOpts{}, + node.Weight, + ) + Expect(err).Should(BeNil()) // Initiate validator registration - nodeID := ids.GenerateTestID() - blsPublicKey := [bls.PublicKeyLen]byte{} receipt, validationID := InitializeNativeValidatorRegistration( ctx, fundedKey, subnetInfo, stakeAmount, - nodeID, - blsPublicKey, + node, + expiry, stakingManager, ) // Gather subnet-evm Warp signatures for the RegisterSubnetValidatorMessage & relay to the P-Chain // (Sending to the P-Chain will be skipped for now) - signedWarpMessage := network.ConstructSignedWarpMessage(ctx, receipt, subnetInfo, pChainInfo) + signedWarpMessage := ConstructSignedWarpMessage(ctx, receipt, subnetInfo, pChainInfo) - weight, err := stakingManager.ValueToWeight( - &bind.CallOpts{}, - stakeAmount, + _, err = network.GetPChainWallet().IssueRegisterSubnetValidatorTx( + 100*units.Avax, + node.NodePoP.ProofOfPossession, + signedWarpMessage.Bytes(), ) Expect(err).Should(BeNil()) - // Validate the Warp message, (this will be done on the P-Chain in the future) - ValidateRegisterSubnetValidatorMessage( - signedWarpMessage, - nodeID, - weight, - subnetInfo.SubnetID, - blsPublicKey, - ) + PChainProposerVMWorkaround(network) + AdvanceProposerVM(ctx, subnetInfo, fundedKey, 5) // Construct a SubnetValidatorRegistrationMessage Warp message from the P-Chain + log.Println("Completing validator registration") registrationSignedMessage := ConstructSubnetValidatorRegistrationMessage( validationID, - 0, - Node{}, - 0, + expiry, + node, true, subnetInfo, pChainInfo, @@ -819,13 +835,17 @@ func InitializeAndCompleteERC20ValidatorRegistration( stakingManager *erc20tokenstakingmanager.ERC20TokenStakingManager, stakingManagerAddress common.Address, erc20 *exampleerc20.ExampleERC20, - stakeAmount *big.Int, - weight uint64, expiry uint64, node Node, ) ids.ID { + stakeAmount, err := stakingManager.WeightToValue( + &bind.CallOpts{}, + node.Weight, + ) + Expect(err).Should(BeNil()) // Initiate validator registration var receipt *types.Receipt + log.Println("Initializing validator registration") receipt, validationID := InitializeERC20ValidatorRegistration( ctx, fundedKey, @@ -839,37 +859,23 @@ func InitializeAndCompleteERC20ValidatorRegistration( ) // Gather subnet-evm Warp signatures for the RegisterSubnetValidatorMessage & relay to the P-Chain - // (Sending to the P-Chain will be skipped for now) - // TODONOW: construct the pre-image of the validationID as the justification - signedWarpMessage := network.ConstructSignedWarpMessage(ctx, receipt, subnetInfo, pChainInfo) - - // weight, err := stakingManager.ValueToWeight( - // &bind.CallOpts{}, - // stakeAmount, - // ) - // Expect(err).Should(BeNil()) - // Validate the Warp message, (this will be done on the P-Chain in the future) - // ValidateRegisterSubnetValidatorMessage( - // signedWarpMessage, - // nodeID, - // weight, - // subnetInfo.SubnetID, - // blsPublicKey, - // ) - _, err := network.GetPChainWallet().IssueRegisterSubnetValidatorTx( - units.Avax, + signedWarpMessage := ConstructSignedWarpMessage(ctx, receipt, subnetInfo, pChainInfo) + + _, err = network.GetPChainWallet().IssueRegisterSubnetValidatorTx( + 100*units.Avax, node.NodePoP.ProofOfPossession, signedWarpMessage.Bytes(), ) Expect(err).Should(BeNil()) PChainProposerVMWorkaround(network) + AdvanceProposerVM(ctx, subnetInfo, fundedKey, 5) // Construct a SubnetValidatorRegistrationMessage Warp message from the P-Chain + log.Println("Completing validator registration") registrationSignedMessage := ConstructSubnetValidatorRegistrationMessage( validationID, expiry, node, - weight, true, subnetInfo, pChainInfo, @@ -906,40 +912,37 @@ func InitializeAndCompletePoAValidatorRegistration( pChainInfo interfaces.SubnetTestInfo, validatorManager *poavalidatormanager.PoAValidatorManager, validatorManagerAddress common.Address, - weight uint64, + expiry uint64, + node Node, ) ids.ID { // Initiate validator registration - nodeID := ids.GenerateTestID() - blsPublicKey := [bls.PublicKeyLen]byte{} receipt, validationID := InitializePoAValidatorRegistration( ctx, ownerKey, subnetInfo, - weight, - nodeID, - blsPublicKey, + node, + expiry, validatorManager, ) // Gather subnet-evm Warp signatures for the RegisterSubnetValidatorMessage & relay to the P-Chain - // (Sending to the P-Chain will be skipped for now) - signedWarpMessage := network.ConstructSignedWarpMessage(ctx, receipt, subnetInfo, pChainInfo) + signedWarpMessage := ConstructSignedWarpMessage(ctx, receipt, subnetInfo, pChainInfo) - // Validate the Warp message, (this will be done on the P-Chain in the future) - ValidateRegisterSubnetValidatorMessage( - signedWarpMessage, - nodeID, - weight, - subnetInfo.SubnetID, - blsPublicKey, + _, err := network.GetPChainWallet().IssueRegisterSubnetValidatorTx( + 100*units.Avax, + node.NodePoP.ProofOfPossession, + signedWarpMessage.Bytes(), ) + Expect(err).Should(BeNil()) + PChainProposerVMWorkaround(network) + AdvanceProposerVM(ctx, subnetInfo, fundedKey, 5) // Construct a SubnetValidatorRegistrationMessage Warp message from the P-Chain + log.Println("Completing validator registration") registrationSignedMessage := ConstructSubnetValidatorRegistrationMessage( validationID, - 0, - Node{}, - 0, + expiry, + node, true, subnetInfo, pChainInfo, @@ -1315,7 +1318,7 @@ func CompleteEndNativeDelegation( ) } -func InitializeAndCompleteEndNativeValidation( +func InitializeAndCompleteEndInitialNativeValidation( ctx context.Context, network interfaces.LocalNetwork, signatureAggregator *aggregator.SignatureAggregator, @@ -1325,9 +1328,10 @@ func InitializeAndCompleteEndNativeValidation( stakingManager *nativetokenstakingmanager.NativeTokenStakingManager, stakingManagerAddress common.Address, validationID ids.ID, + index uint32, weight uint64, - nonce uint64, ) { + log.Println("Initializing initial validator removal") WaitMinStakeDuration(ctx, subnetInfo, fundedKey) receipt := ForceInitializeEndNativeValidation( ctx, @@ -1346,18 +1350,102 @@ func InitializeAndCompleteEndNativeValidation( // Gather subnet-evm Warp signatures for the SetSubnetValidatorWeightMessage & relay to the P-Chain // (Sending to the P-Chain will be skipped for now) - signedWarpMessage := network.ConstructSignedWarpMessage(ctx, receipt, subnetInfo, pChainInfo) + unsignedMessage := ExtractWarpMessageFromLog(ctx, receipt, subnetInfo) + signedWarpMessage, err := signatureAggregator.CreateSignedMessage( + unsignedMessage, + nil, + subnetInfo.SubnetID, + 67, + ) Expect(err).Should(BeNil()) - // Validate the Warp message, (this will be done on the P-Chain in the future) - ValidateSubnetValidatorWeightMessage(signedWarpMessage, validationID, 0, nonce) + // Deliver the Warp message to the P-Chain + network.GetPChainWallet().IssueSetSubnetValidatorWeightTx(signedWarpMessage.Bytes()) + PChainProposerVMWorkaround(network) + AdvanceProposerVM(ctx, subnetInfo, fundedKey, 5) + + // Construct a SubnetValidatorRegistrationMessage Warp message from the P-Chain + log.Println("Completing initial validator removal") + registrationSignedMessage := ConstructSubnetValidatorRegistrationMessageForInitialValidator( + validationID, + index, + false, + subnetInfo, + pChainInfo, + network, + signatureAggregator, + ) + + // Deliver the Warp message to the subnet + receipt = CompleteEndNativeValidation( + ctx, + fundedKey, + subnetInfo, + stakingManagerAddress, + registrationSignedMessage, + ) + + // Check that the validator is has been delisted from the staking contract + validationEndedEvent, err := GetEventFromLogs( + receipt.Logs, + stakingManager.ParseValidationPeriodEnded, + ) + Expect(err).Should(BeNil()) + Expect(validationEndedEvent.ValidationID[:]).Should(Equal(validationID[:])) +} + +func InitializeAndCompleteEndNativeValidation( + ctx context.Context, + network interfaces.LocalNetwork, + signatureAggregator *aggregator.SignatureAggregator, + fundedKey *ecdsa.PrivateKey, + subnetInfo interfaces.SubnetTestInfo, + pChainInfo interfaces.SubnetTestInfo, + stakingManager *nativetokenstakingmanager.NativeTokenStakingManager, + stakingManagerAddress common.Address, + validationID ids.ID, + expiry uint64, + node Node, + nonce uint64, +) { + log.Println("Initializing validator removal") + WaitMinStakeDuration(ctx, subnetInfo, fundedKey) + receipt := ForceInitializeEndNativeValidation( + ctx, + fundedKey, + subnetInfo, + stakingManager, + validationID, + ) + validatorRemovalEvent, err := GetEventFromLogs( + receipt.Logs, + stakingManager.ParseValidatorRemovalInitialized, + ) + Expect(err).Should(BeNil()) + Expect(validatorRemovalEvent.ValidationID[:]).Should(Equal(validationID[:])) + Expect(validatorRemovalEvent.Weight.Uint64()).Should(Equal(node.Weight)) + + // Gather subnet-evm Warp signatures for the SetSubnetValidatorWeightMessage & relay to the P-Chain + unsignedMessage := ExtractWarpMessageFromLog(ctx, receipt, subnetInfo) + signedWarpMessage, err := signatureAggregator.CreateSignedMessage( + unsignedMessage, + nil, + subnetInfo.SubnetID, + 67, + ) + Expect(err).Should(BeNil()) + + // Deliver the Warp message to the P-Chain + network.GetPChainWallet().IssueSetSubnetValidatorWeightTx(signedWarpMessage.Bytes()) + PChainProposerVMWorkaround(network) + AdvanceProposerVM(ctx, subnetInfo, fundedKey, 5) // Construct a SubnetValidatorRegistrationMessage Warp message from the P-Chain + log.Println("Completing validator removal") registrationSignedMessage := ConstructSubnetValidatorRegistrationMessage( validationID, - 0, - Node{}, - 0, + expiry, + node, false, subnetInfo, pChainInfo, @@ -1383,6 +1471,82 @@ func InitializeAndCompleteEndNativeValidation( Expect(registrationEvent.ValidationID[:]).Should(Equal(validationID[:])) } +func InitializeAndCompleteEndInitialERC20Validation( + ctx context.Context, + network interfaces.LocalNetwork, + signatureAggregator *aggregator.SignatureAggregator, + fundedKey *ecdsa.PrivateKey, + subnetInfo interfaces.SubnetTestInfo, + pChainInfo interfaces.SubnetTestInfo, + stakingManager *erc20tokenstakingmanager.ERC20TokenStakingManager, + stakingManagerAddress common.Address, + validationID ids.ID, + index uint32, + weight uint64, +) { + log.Println("Initializing initial validator removal") + WaitMinStakeDuration(ctx, subnetInfo, fundedKey) + receipt := ForceInitializeEndERC20Validation( + ctx, + fundedKey, + subnetInfo, + stakingManager, + validationID, + ) + validatorRemovalEvent, err := GetEventFromLogs( + receipt.Logs, + stakingManager.ParseValidatorRemovalInitialized, + ) + Expect(err).Should(BeNil()) + Expect(validatorRemovalEvent.ValidationID[:]).Should(Equal(validationID[:])) + Expect(validatorRemovalEvent.Weight.Uint64()).Should(Equal(weight)) + + // Gather subnet-evm Warp signatures for the SetSubnetValidatorWeightMessage & relay to the P-Chain + // (Sending to the P-Chain will be skipped for now) + unsignedMessage := ExtractWarpMessageFromLog(ctx, receipt, subnetInfo) + signedWarpMessage, err := signatureAggregator.CreateSignedMessage( + unsignedMessage, + nil, + subnetInfo.SubnetID, + 67, + ) + Expect(err).Should(BeNil()) + + // Deliver the Warp message to the P-Chain + network.GetPChainWallet().IssueSetSubnetValidatorWeightTx(signedWarpMessage.Bytes()) + PChainProposerVMWorkaround(network) + AdvanceProposerVM(ctx, subnetInfo, fundedKey, 5) + + // Construct a SubnetValidatorRegistrationMessage Warp message from the P-Chain + log.Println("Completing initial validator removal") + registrationSignedMessage := ConstructSubnetValidatorRegistrationMessageForInitialValidator( + validationID, + index, + false, + subnetInfo, + pChainInfo, + network, + signatureAggregator, + ) + + // Deliver the Warp message to the subnet + receipt = CompleteEndERC20Validation( + ctx, + fundedKey, + subnetInfo, + stakingManagerAddress, + registrationSignedMessage, + ) + + // Check that the validator is has been delisted from the staking contract + validationEndedEvent, err := GetEventFromLogs( + receipt.Logs, + stakingManager.ParseValidationPeriodEnded, + ) + Expect(err).Should(BeNil()) + Expect(validationEndedEvent.ValidationID[:]).Should(Equal(validationID[:])) +} + func InitializeAndCompleteEndERC20Validation( ctx context.Context, network interfaces.LocalNetwork, @@ -1395,9 +1559,9 @@ func InitializeAndCompleteEndERC20Validation( validationID ids.ID, expiry uint64, node Node, - weight uint64, nonce uint64, ) { + log.Println("Initializing validator removal") WaitMinStakeDuration(ctx, subnetInfo, fundedKey) receipt := ForceInitializeEndERC20Validation( ctx, @@ -1412,11 +1576,10 @@ func InitializeAndCompleteEndERC20Validation( ) Expect(err).Should(BeNil()) Expect(validatorRemovalEvent.ValidationID[:]).Should(Equal(validationID[:])) - Expect(validatorRemovalEvent.Weight.Uint64()).Should(Equal(weight)) + Expect(validatorRemovalEvent.Weight.Uint64()).Should(Equal(node.Weight)) // Gather subnet-evm Warp signatures for the SetSubnetValidatorWeightMessage & relay to the P-Chain - // (Sending to the P-Chain will be skipped for now) - unsignedMessage := network.ExtractWarpMessageFromLog(ctx, receipt, subnetInfo) + unsignedMessage := ExtractWarpMessageFromLog(ctx, receipt, subnetInfo) signedWarpMessage, err := signatureAggregator.CreateSignedMessage( unsignedMessage, nil, @@ -1424,20 +1587,18 @@ func InitializeAndCompleteEndERC20Validation( 67, ) Expect(err).Should(BeNil()) - log.Println("SetSubnetValidatorWeightMessage") - log.Println(signedWarpMessage.Signature.NumSigners()) - log.Println(signedWarpMessage.Signature.String()) - log.Println(signedWarpMessage.SourceChainID.String()) // Deliver the Warp message to the P-Chain network.GetPChainWallet().IssueSetSubnetValidatorWeightTx(signedWarpMessage.Bytes()) PChainProposerVMWorkaround(network) + AdvanceProposerVM(ctx, subnetInfo, fundedKey, 5) + // Construct a SubnetValidatorRegistrationMessage Warp message from the P-Chain + log.Println("Completing validator removal") registrationSignedMessage := ConstructSubnetValidatorRegistrationMessage( validationID, expiry, node, - weight, false, subnetInfo, pChainInfo, @@ -1455,12 +1616,89 @@ func InitializeAndCompleteEndERC20Validation( ) // Check that the validator is has been delisted from the staking contract - registrationEvent, err := GetEventFromLogs( + validationEndedEvent, err := GetEventFromLogs( receipt.Logs, stakingManager.ParseValidationPeriodEnded, ) Expect(err).Should(BeNil()) - Expect(registrationEvent.ValidationID[:]).Should(Equal(validationID[:])) + Expect(validationEndedEvent.ValidationID[:]).Should(Equal(validationID[:])) +} + +func InitializeAndCompleteEndInitialPoAValidation( + ctx context.Context, + network interfaces.LocalNetwork, + signatureAggregator *aggregator.SignatureAggregator, + ownerKey *ecdsa.PrivateKey, + fundedKey *ecdsa.PrivateKey, + subnetInfo interfaces.SubnetTestInfo, + pChainInfo interfaces.SubnetTestInfo, + stakingManager *poavalidatormanager.PoAValidatorManager, + stakingManagerAddress common.Address, + validationID ids.ID, + index uint32, + weight uint64, +) { + log.Println("Initializing initial validator removal") + WaitMinStakeDuration(ctx, subnetInfo, fundedKey) + receipt := InitializeEndPoAValidation( + ctx, + ownerKey, + subnetInfo, + stakingManager, + validationID, + ) + validatorRemovalEvent, err := GetEventFromLogs( + receipt.Logs, + stakingManager.ParseValidatorRemovalInitialized, + ) + Expect(err).Should(BeNil()) + Expect(validatorRemovalEvent.ValidationID[:]).Should(Equal(validationID[:])) + Expect(validatorRemovalEvent.Weight.Uint64()).Should(Equal(weight)) + + // Gather subnet-evm Warp signatures for the SetSubnetValidatorWeightMessage & relay to the P-Chain + // (Sending to the P-Chain will be skipped for now) + unsignedMessage := ExtractWarpMessageFromLog(ctx, receipt, subnetInfo) + signedWarpMessage, err := signatureAggregator.CreateSignedMessage( + unsignedMessage, + nil, + subnetInfo.SubnetID, + 67, + ) + Expect(err).Should(BeNil()) + + // Deliver the Warp message to the P-Chain + network.GetPChainWallet().IssueSetSubnetValidatorWeightTx(signedWarpMessage.Bytes()) + PChainProposerVMWorkaround(network) + AdvanceProposerVM(ctx, subnetInfo, fundedKey, 5) + + // Construct a SubnetValidatorRegistrationMessage Warp message from the P-Chain + log.Println("Completing initial validator removal") + registrationSignedMessage := ConstructSubnetValidatorRegistrationMessageForInitialValidator( + validationID, + index, + false, + subnetInfo, + pChainInfo, + network, + signatureAggregator, + ) + + // Deliver the Warp message to the subnet + receipt = CompleteEndPoAValidation( + ctx, + fundedKey, + subnetInfo, + stakingManagerAddress, + registrationSignedMessage, + ) + + // Check that the validator is has been delisted from the staking contract + validationEndedEvent, err := GetEventFromLogs( + receipt.Logs, + stakingManager.ParseValidationPeriodEnded, + ) + Expect(err).Should(BeNil()) + Expect(validationEndedEvent.ValidationID[:]).Should(Equal(validationID[:])) } func InitializeAndCompleteEndPoAValidation( @@ -1494,7 +1732,7 @@ func InitializeAndCompleteEndPoAValidation( // Gather subnet-evm Warp signatures for the SetSubnetValidatorWeightMessage & relay to the P-Chain // (Sending to the P-Chain will be skipped for now) - signedWarpMessage := network.ConstructSignedWarpMessage(ctx, receipt, subnetInfo, pChainInfo) + signedWarpMessage := ConstructSignedWarpMessage(ctx, receipt, subnetInfo, pChainInfo) Expect(err).Should(BeNil()) // Validate the Warp message, (this will be done on the P-Chain in the future) @@ -1505,7 +1743,6 @@ func InitializeAndCompleteEndPoAValidation( validationID, 0, Node{}, - 0, false, subnetInfo, pChainInfo, @@ -1535,29 +1772,77 @@ func InitializeAndCompleteEndPoAValidation( // P-Chain utils // +func ConstructSubnetValidatorRegistrationMessageForInitialValidator( + validationID ids.ID, + index uint32, + valid bool, + subnet interfaces.SubnetTestInfo, + pChainInfo interfaces.SubnetTestInfo, + network interfaces.LocalNetwork, + signatureAggregator *aggregator.SignatureAggregator, +) *avalancheWarp.Message { + justification := platformvm.SubnetValidatorRegistrationJustification{ + Preimage: &platformvm.SubnetValidatorRegistrationJustification_ConvertSubnetTxData{ + ConvertSubnetTxData: &platformvm.SubnetIDIndex{ + SubnetId: subnet.SubnetID[:], + Index: index, + }, + }, + } + justificationBytes, err := proto.Marshal(&justification) + Expect(err).Should(BeNil()) + + registrationPayload, err := warpMessage.NewSubnetValidatorRegistration(validationID, valid) + Expect(err).Should(BeNil()) + registrationAddressedCall, err := warpPayload.NewAddressedCall(nil, registrationPayload.Bytes()) + Expect(err).Should(BeNil()) + registrationUnsignedMessage, err := avalancheWarp.NewUnsignedMessage( + network.GetNetworkID(), + pChainInfo.BlockchainID, + registrationAddressedCall.Bytes(), + ) + Expect(err).Should(BeNil()) + + registrationSignedMessage, err := signatureAggregator.CreateSignedMessage( + registrationUnsignedMessage, + justificationBytes, + subnet.SubnetID, + 67, + ) + Expect(err).Should(BeNil()) + + return registrationSignedMessage +} + func ConstructSubnetValidatorRegistrationMessage( validationID ids.ID, expiry uint64, node Node, - weight uint64, valid bool, subnet interfaces.SubnetTestInfo, pChainInfo interfaces.SubnetTestInfo, network interfaces.LocalNetwork, signatureAggregator *aggregator.SignatureAggregator, ) *avalancheWarp.Message { - justification, err := warpMessages.NewRegisterSubnetValidator( + msg, err := warpMessage.NewRegisterSubnetValidator( subnet.SubnetID, node.NodeID, node.NodePoP.PublicKey, expiry, - warpMessages.PChainOwner{}, - warpMessages.PChainOwner{}, - weight, + warpMessage.PChainOwner{}, + warpMessage.PChainOwner{}, + node.Weight, ) Expect(err).Should(BeNil()) + justification := platformvm.SubnetValidatorRegistrationJustification{ + Preimage: &platformvm.SubnetValidatorRegistrationJustification_RegisterSubnetValidatorMessage{ + RegisterSubnetValidatorMessage: msg.Bytes(), + }, + } + justificationBytes, err := proto.Marshal(&justification) + Expect(err).Should(BeNil()) - registrationPayload, err := warpMessages.NewSubnetValidatorRegistration(validationID, valid) + registrationPayload, err := warpMessage.NewSubnetValidatorRegistration(validationID, valid) Expect(err).Should(BeNil()) registrationAddressedCall, err := warpPayload.NewAddressedCall(nil, registrationPayload.Bytes()) Expect(err).Should(BeNil()) @@ -1570,15 +1855,12 @@ func ConstructSubnetValidatorRegistrationMessage( registrationSignedMessage, err := signatureAggregator.CreateSignedMessage( registrationUnsignedMessage, - justification.Bytes(), + justificationBytes, subnet.SubnetID, 67, ) - log.Println("registrationSignedMessage") - log.Println(registrationSignedMessage.Signature.NumSigners()) - log.Println(registrationSignedMessage.Signature.String()) - log.Println(registrationSignedMessage.SourceChainID.String()) Expect(err).Should(BeNil()) + return registrationSignedMessage } @@ -1591,7 +1873,7 @@ func ConstructSubnetValidatorWeightUpdateMessage( network interfaces.LocalNetwork, signatureAggregator *aggregator.SignatureAggregator, ) *avalancheWarp.Message { - payload, err := warpMessages.NewSubnetValidatorWeight(validationID, nonce, weight) + payload, err := warpMessage.NewSubnetValidatorWeight(validationID, nonce, weight) Expect(err).Should(BeNil()) updateAddressedCall, err := warpPayload.NewAddressedCall(nil, payload.Bytes()) Expect(err).Should(BeNil()) @@ -1619,7 +1901,7 @@ func ConstructSubnetConversionMessage( network interfaces.LocalNetwork, signatureAggregator *aggregator.SignatureAggregator, ) *avalancheWarp.Message { - subnetConversionPayload, err := warpMessages.NewSubnetConversion(subnetConversionID) + subnetConversionPayload, err := warpMessage.NewSubnetConversion(subnetConversionID) Expect(err).Should(BeNil()) subnetConversionAddressedCall, err := warpPayload.NewAddressedCall( nil, @@ -1659,13 +1941,13 @@ func ValidateRegisterSubnetValidatorMessage( msg, err := warpPayload.ParseAddressedCall(signedWarpMessage.UnsignedMessage.Payload) Expect(err).Should(BeNil()) // Check that the addressed call payload is a registered Warp message type - var payloadInterface warpMessages.Payload - ver, err := warpMessages.Codec.Unmarshal(msg.Payload, &payloadInterface) + var payloadInterface warpMessage.Payload + ver, err := warpMessage.Codec.Unmarshal(msg.Payload, &payloadInterface) Expect(err).Should(BeNil()) - payload, ok := payloadInterface.(*warpMessages.RegisterSubnetValidator) + payload, ok := payloadInterface.(*warpMessage.RegisterSubnetValidator) Expect(ok).Should(BeTrue()) - Expect(ver).Should(Equal(uint16(warpMessages.CodecVersion))) + Expect(ver).Should(Equal(uint16(warpMessage.CodecVersion))) Expect(payload.NodeID).Should(Equal(nodeID)) Expect(payload.Weight).Should(Equal(weight)) Expect(payload.SubnetID).Should(Equal(subnetID)) @@ -1681,13 +1963,13 @@ func ValidateSubnetValidatorWeightMessage( msg, err := warpPayload.ParseAddressedCall(signedWarpMessage.UnsignedMessage.Payload) Expect(err).Should(BeNil()) // Check that the addressed call payload is a registered Warp message type - var payloadInterface warpMessages.Payload - ver, err := warpMessages.Codec.Unmarshal(msg.Payload, &payloadInterface) + var payloadInterface warpMessage.Payload + ver, err := warpMessage.Codec.Unmarshal(msg.Payload, &payloadInterface) Expect(err).Should(BeNil()) - payload, ok := payloadInterface.(*warpMessages.SubnetValidatorWeight) + payload, ok := payloadInterface.(*warpMessage.SubnetValidatorWeight) Expect(ok).Should(BeTrue()) - Expect(ver).Should(Equal(uint16(warpMessages.CodecVersion))) + Expect(ver).Should(Equal(uint16(warpMessage.CodecVersion))) Expect(payload.ValidationID).Should(Equal(validationID)) Expect(payload.Weight).Should(Equal(weight)) Expect(payload.Nonce).Should(Equal(nonce)) @@ -1774,7 +2056,7 @@ func PackSubnetConversionData(data interface{}) ([]byte, error) { } b := make([]byte, 94+packedInitialValidatorsLen) - binary.BigEndian.PutUint16(b[0:2], uint16(warpMessages.CodecVersion)) + binary.BigEndian.PutUint16(b[0:2], uint16(warpMessage.CodecVersion)) copy(b[2:34], subnetID[:]) copy(b[34:66], validatorManagerBlockchainID[:]) // These are evm addresses and have lengths of 20 so hardcoding here @@ -1838,9 +2120,8 @@ func PackInitialValidator(iv interface{}) ([]byte, error) { func PChainProposerVMWorkaround( network interfaces.LocalNetwork, ) { - // // Workaround current block map rules - destAddrStr := "P-local18jma8ppw3nhx5r4ap8clazz0dps7rv5u00z96u" - destAddr, err := address.ParseToID(destAddrStr) + // Workaround current block map rules + destAddr, err := address.ParseToID(DefaultPChainAddress) Expect(err).Should(BeNil()) log.Println("Waiting for P-Chain...") time.Sleep(30 * time.Second) @@ -1892,3 +2173,91 @@ func PChainProposerVMWorkaround( Expect(err).Should(BeNil()) // End workaround } + +func AdvanceProposerVM( + ctx context.Context, + subnet interfaces.SubnetTestInfo, + fundedKey *ecdsa.PrivateKey, + blocks int, +) { + for i := 0; i < blocks; i++ { + err := subnetEvmUtils.IssueTxsToActivateProposerVMFork( + ctx, subnet.EVMChainID, fundedKey, subnet.WSClient, + ) + Expect(err).Should(BeNil()) + } +} + +func ConvertSubnet( + ctx context.Context, + subnetInfo interfaces.SubnetTestInfo, + network interfaces.LocalNetwork, + stakingManagerAddress common.Address, + fundedKey *ecdsa.PrivateKey, +) []Node { + // Remove the current validators before converting the subnet + var nodes []Node + for _, uri := range subnetInfo.NodeURIs { + infoClient := info.NewClient(uri) + nodeID, nodePoP, err := infoClient.GetNodeID(ctx) + Expect(err).Should(BeNil()) + nodes = append(nodes, Node{ + NodeID: nodeID, + NodePoP: nodePoP, + }) + + _, err = network.GetPChainWallet().IssueRemoveSubnetValidatorTx( + nodeID, + subnetInfo.SubnetID, + ) + Expect(err).Should(BeNil()) + } + + // Sort the nodeIDs so that the subnet conversion ID matches the P-Chain + sort.Slice(nodes, func(i, j int) bool { + return string(nodes[i].NodeID.Bytes()) < string(nodes[j].NodeID.Bytes()) + }) + + totalWeight := uint64(len(nodes)-1) * units.Schmeckle + for i := 0; i < len(nodes)-1; i++ { + nodes[i].Weight = units.Schmeckle + totalWeight += units.Schmeckle + } + // Set the last node's weight such that removing any other node will not violate the churn limit + nodes[len(nodes)-1].Weight = 4 * totalWeight + + // Construct the convert subnet info + destAddr, err := address.ParseToID(DefaultPChainAddress) + Expect(err).Should(BeNil()) + vdrs := make([]*txs.ConvertSubnetValidator, len(nodes)) + for i, node := range nodes { + vdrs[i] = &txs.ConvertSubnetValidator{ + NodeID: node.NodeID.Bytes(), + Weight: nodes[i].Weight, + Balance: units.Avax * 100, + Signer: *node.NodePoP, + RemainingBalanceOwner: warpMessage.PChainOwner{ + Threshold: 1, + Addresses: []ids.ShortID{destAddr}, + }, + DeactivationOwner: warpMessage.PChainOwner{ + Threshold: 1, + Addresses: []ids.ShortID{destAddr}, + }, + } + } + + log.Println("Issuing ConvertSubnetTx") + _, err = network.GetPChainWallet().IssueConvertSubnetTx( + subnetInfo.SubnetID, + subnetInfo.BlockchainID, + stakingManagerAddress[:], + vdrs, + ) + Expect(err).Should(BeNil()) + + PChainProposerVMWorkaround(network) + AdvanceProposerVM(ctx, subnetInfo, fundedKey, 5) + + return nodes +} diff --git a/utils/deployment-utils/deployment_utils.go b/utils/deployment-utils/deployment_utils.go index a12dbaf12..3f0ba81ca 100644 --- a/utils/deployment-utils/deployment_utils.go +++ b/utils/deployment-utils/deployment_utils.go @@ -126,8 +126,6 @@ func ConstructKeylessTransaction( contractAddress := crypto.CreateAddress(senderAddress, 0) contractAddressString := contractAddress.Hex() // "0x" prepended by Hex() already. - log.Println("Raw Teleporter Contract Creation Transaction:") - log.Println(contractCreationTxString) log.Println("Teleporter Contract Keyless Deployer Address: ", senderAddressString) log.Println("Teleporter Messenger Universal Contract Address: ", contractAddressString)