diff --git a/tests/flows/check_upgrade_access.go b/tests/flows/check_upgrade_access.go new file mode 100644 index 000000000..6d58312c4 --- /dev/null +++ b/tests/flows/check_upgrade_access.go @@ -0,0 +1,92 @@ +package flows + +import ( + "context" + "math/big" + + "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/ethereum/go-ethereum/crypto" + . "github.com/onsi/gomega" +) + +func CheckUpgradeAccess(network interfaces.Network) { + subnetInfo := network.GetPrimaryNetworkInfo() + fundedAddress, fundedKey := network.GetFundedAccountInfo() + + // + // Deploy ExampleMessenger to the subnet + // + ctx := context.Background() + teleporterAddress := network.GetTeleporterContractAddress() + _, exampleMessenger := utils.DeployExampleCrossChainMessenger( + ctx, + fundedKey, + fundedAddress, + subnetInfo, + ) + + // Try to call updateMinTeleporterVersion from a non owner account + nonOwnerKey, err := crypto.GenerateKey() + Expect(err).Should(BeNil()) + nonOwnerAddress := crypto.PubkeyToAddress(nonOwnerKey.PublicKey) + + // Transfer native assets to the non owner account + fundAmount := big.NewInt(1e18) // 1eth + utils.SendNativeTransfer( + ctx, + subnetInfo, + fundedKey, + nonOwnerAddress, + fundAmount, + ) + + // Check that access is not granted to the non owner and has no effect + nonOwnerOpts, err := bind.NewKeyedTransactorWithChainID( + nonOwnerKey, subnetInfo.EVMChainID) + Expect(err).Should(BeNil()) + _, err = exampleMessenger.PauseTeleporterAddress(nonOwnerOpts, teleporterAddress) + Expect(err).ShouldNot(BeNil()) + Expect(err.Error()).Should(ContainSubstring(errCallerNotOwnerStr)) + + // Check that the teleporter address is not paused, because previous call should have failed + isPaused, err := exampleMessenger.IsTeleporterAddressPaused(&bind.CallOpts{}, teleporterAddress) + Expect(err).Should(BeNil()) + Expect(isPaused).Should(BeFalse()) + + // Check that the owner is able to pause the Teleporter address + ownerOpts, err := bind.NewKeyedTransactorWithChainID( + fundedKey, subnetInfo.EVMChainID) + Expect(err).Should(BeNil()) + // Try to call pauseTeleporterAddress from the owner account + tx, err := exampleMessenger.PauseTeleporterAddress(ownerOpts, teleporterAddress) + Expect(err).Should(BeNil()) + utils.WaitForTransactionSuccess(ctx, subnetInfo, tx) + isPaused, err = exampleMessenger.IsTeleporterAddressPaused(&bind.CallOpts{}, teleporterAddress) + Expect(err).Should(BeNil()) + Expect(isPaused).Should(BeTrue()) + + // Transfer ownership to the non owner account + tx, err = exampleMessenger.TransferOwnership(ownerOpts, nonOwnerAddress) + Expect(err).Should(BeNil()) + utils.WaitForTransactionSuccess(ctx, subnetInfo, tx) + + // Try to call unpauseTeleporterAddress from the previous owner account + _, err = exampleMessenger.UnpauseTeleporterAddress(ownerOpts, teleporterAddress) + Expect(err).ShouldNot(BeNil()) + Expect(err.Error()).Should(ContainSubstring(errCallerNotOwnerStr)) + + // Make sure the teleporter address is still paused + isPaused, err = exampleMessenger.IsTeleporterAddressPaused(&bind.CallOpts{}, teleporterAddress) + Expect(err).Should(BeNil()) + Expect(isPaused).Should(BeTrue()) + + // Try to call unpauseTeleporterAddress from the non owner account now + tx, err = exampleMessenger.UnpauseTeleporterAddress(nonOwnerOpts, teleporterAddress) + Expect(err).Should(BeNil()) + utils.WaitForTransactionSuccess(ctx, subnetInfo, tx) + isPaused, err = exampleMessenger.IsTeleporterAddressPaused(&bind.CallOpts{}, teleporterAddress) + Expect(err).Should(BeNil()) + Expect(isPaused).Should(BeFalse()) +} diff --git a/tests/flows/errors.go b/tests/flows/errors.go new file mode 100644 index 000000000..2e0221970 --- /dev/null +++ b/tests/flows/errors.go @@ -0,0 +1,6 @@ +package flows + +const ( + // Error message from OpenZeppelin's Ownable.sol + errCallerNotOwnerStr = "Ownable: caller is not the owner" +) diff --git a/tests/local/e2e_test.go b/tests/local/e2e_test.go index 7c2a3c1c0..1f23ece91 100644 --- a/tests/local/e2e_test.go +++ b/tests/local/e2e_test.go @@ -17,6 +17,11 @@ import ( const ( teleporterByteCodeFile = "./contracts/out/TeleporterMessenger.sol/TeleporterMessenger.json" warpGenesisFile = "./tests/utils/warp-genesis.json" + + crossChainAppsLabel = "cross chain apps" + teleporterMessengerLabel = "TeleporterMessenger" + upgradeabilityLabel = "upgradeability" + utilsLabel = "utils" ) var ( @@ -66,106 +71,111 @@ var _ = ginkgo.AfterSuite(func() { var _ = ginkgo.Describe("[Teleporter integration tests]", func() { // Cross-chain application tests ginkgo.It("Send native tokens from subnet A to B and back", - ginkgo.Label("cross chain apps"), + ginkgo.Label(crossChainAppsLabel), func() { flows.NativeTokenBridge(LocalNetworkInstance) }) ginkgo.It("Send ERC20 tokens from subnet A to Native tokens on subnet B and back", - ginkgo.Label("cross chain apps"), + ginkgo.Label(crossChainAppsLabel), func() { flows.ERC20ToNativeTokenBridge(LocalNetworkInstance) }) ginkgo.It("Example cross chain messenger", - ginkgo.Label("cross chain apps"), + ginkgo.Label(crossChainAppsLabel), func() { flows.ExampleMessenger(LocalNetworkInstance) }) ginkgo.It("ERC20 bridge multihop", - ginkgo.Label("cross chain apps"), + ginkgo.Label(crossChainAppsLabel), func() { flows.ERC20BridgeMultihop(LocalNetworkInstance) }) ginkgo.It("Block hash publish and receive", - ginkgo.Label("cross chain apps"), + ginkgo.Label(crossChainAppsLabel), func() { flows.BlockHashPublishReceive(LocalNetworkInstance) }) // Teleporter tests ginkgo.It("Send a message from Subnet A to Subnet B, and one from B to A", - ginkgo.Label("TeleporterMessenger"), + ginkgo.Label(teleporterMessengerLabel), func() { flows.BasicSendReceive(LocalNetworkInstance) }) ginkgo.It("Deliver to the wrong chain", - ginkgo.Label("TeleporterMessenger"), + ginkgo.Label(teleporterMessengerLabel), func() { flows.DeliverToWrongChain(LocalNetworkInstance) }) ginkgo.It("Deliver to non-existent contract", - ginkgo.Label("TeleporterMessenger"), + ginkgo.Label(teleporterMessengerLabel), func() { flows.DeliverToNonExistentContract(LocalNetworkInstance) }) ginkgo.It("Retry successful execution", - ginkgo.Label("TeleporterMessenger"), + ginkgo.Label(teleporterMessengerLabel), func() { flows.RetrySuccessfulExecution(LocalNetworkInstance) }) ginkgo.It("Unallowed relayer", - ginkgo.Label("TeleporterMessenger"), + ginkgo.Label(teleporterMessengerLabel), func() { flows.UnallowedRelayer(LocalNetworkInstance) }) ginkgo.It("Relay message twice", - ginkgo.Label("TeleporterMessenger"), + ginkgo.Label(teleporterMessengerLabel), func() { flows.RelayMessageTwice(LocalNetworkInstance) }) ginkgo.It("Add additional fee amount", - ginkgo.Label("TeleporterMessenger"), + ginkgo.Label(teleporterMessengerLabel), func() { flows.AddFeeAmount(LocalNetworkInstance) }) ginkgo.It("Send specific receipts", - ginkgo.Label("TeleporterMessenger"), + ginkgo.Label(teleporterMessengerLabel), func() { flows.SendSpecificReceipts(LocalNetworkInstance) }) ginkgo.It("Insufficient gas", - ginkgo.Label("TeleporterMessenger"), + ginkgo.Label(teleporterMessengerLabel), func() { flows.InsufficientGas(LocalNetworkInstance) }) ginkgo.It("Resubmit altered message", - ginkgo.Label("TeleporterMessenger"), + ginkgo.Label(teleporterMessengerLabel), func() { flows.ResubmitAlteredMessage(LocalNetworkInstance) }) + ginkgo.It("Check upgrade access", + ginkgo.Label(upgradeabilityLabel), + func() { + flows.CheckUpgradeAccess(LocalNetworkInstance) + }) ginkgo.It("Pause and Unpause Teleporter", - ginkgo.Label("upgradeability"), + ginkgo.Label(upgradeabilityLabel), func() { flows.PauseTeleporter(LocalNetworkInstance) }) ginkgo.It("Calculate Teleporter message IDs", - ginkgo.Label("utils"), + ginkgo.Label(utilsLabel), func() { flows.CalculateMessageID(LocalNetworkInstance) }) // The following tests require special behavior by the relayer, so we only run them on a local network ginkgo.It("Relayer modifies message", - ginkgo.Label("TeleporterMessenger"), + ginkgo.Label(teleporterMessengerLabel), func() { flows.RelayerModifiesMessage(LocalNetworkInstance) }) ginkgo.It("Teleporter registry", - ginkgo.Label("upgradeability"), + ginkgo.Label(upgradeabilityLabel), func() { flows.TeleporterRegistry(LocalNetworkInstance) }) ginkgo.It("Validator churn", - ginkgo.Label("TeleporterMessenger"), + ginkgo.Label(teleporterMessengerLabel), func() { flows.ValidatorChurn(LocalNetworkInstance) })