From 1329066fe4dedf37a0a17a994c82337e84b2cf6c Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Mon, 9 Dec 2024 09:27:38 -0800 Subject: [PATCH] chore(e2e): tolerate multiple runs of precompile tests (#3256) --- cmd/zetae2e/local/local.go | 24 ++++-- e2e/e2etests/helpers.go | 10 +++ e2e/e2etests/test_precompiles_bank.go | 79 ++++++++++++++----- .../test_precompiles_bank_through_contract.go | 59 ++++++++------ 4 files changed, 122 insertions(+), 50 deletions(-) diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index c95c4e9942..fdc47263e9 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -218,6 +218,9 @@ func localE2ETest(cmd *cobra.Command, _ []string) { })) } + e2eStartHeight, err := deployerRunner.Clients.Zetacore.GetBlockHeight(ctx) + noError(err) + // setting up the networks if !skipSetup { logger.Print("⚙️ setting up networks") @@ -258,8 +261,6 @@ func localE2ETest(cmd *cobra.Command, _ []string) { deployerRunner.UpdateChainParamsV2Contracts() deployerRunner.ERC20CustodyAddr = deployerRunner.ERC20CustodyV2Addr - deployerRunner.MintERC20OnEvm(1e10) - logger.Print("✅ setup completed in %s", time.Since(startTime)) } @@ -284,6 +285,9 @@ func localE2ETest(cmd *cobra.Command, _ []string) { os.Exit(0) } + // always mint ERC20 before every test execution + deployerRunner.MintERC20OnEvm(1e10) + // run the v2 migration if testV2Migration { deployerRunner.RunV2Migration() @@ -368,15 +372,23 @@ func localE2ETest(cmd *cobra.Command, _ []string) { precompiledContractTests = []string{ e2etests.TestPrecompilesPrototypeName, e2etests.TestPrecompilesPrototypeThroughContractName, - e2etests.TestPrecompilesStakingName, // Disabled until further notice, check https://github.com/zeta-chain/node/issues/3005. // e2etests.TestPrecompilesStakingThroughContractName, e2etests.TestPrecompilesBankName, e2etests.TestPrecompilesBankFailName, e2etests.TestPrecompilesBankThroughContractName, - e2etests.TestPrecompilesDistributeName, - e2etests.TestPrecompilesDistributeNonZRC20Name, - e2etests.TestPrecompilesDistributeThroughContractName, + } + if e2eStartHeight < 100 { + // these tests require a clean system + // since unstaking has an unbonding period + precompiledContractTests = append(precompiledContractTests, + e2etests.TestPrecompilesStakingName, + e2etests.TestPrecompilesDistributeName, + e2etests.TestPrecompilesDistributeNonZRC20Name, + e2etests.TestPrecompilesDistributeThroughContractName, + ) + } else { + logger.Print("⚠️ partial precompiled run (unclean state)") } } diff --git a/e2e/e2etests/helpers.go b/e2e/e2etests/helpers.go index a7a997d70b..b3d27a7029 100644 --- a/e2e/e2etests/helpers.go +++ b/e2e/e2etests/helpers.go @@ -185,3 +185,13 @@ func parseBitcoinWithdrawArgs(r *runner.E2ERunner, args []string, defaultReceive return receiver, amount } + +// bigAdd is shorthand for new(big.Int).Add(x, y) +func bigAdd(x *big.Int, y *big.Int) *big.Int { + return new(big.Int).Add(x, y) +} + +// bigSub is shorthand for new(big.Int).Sub(x, y) +func bigSub(x *big.Int, y *big.Int) *big.Int { + return new(big.Int).Sub(x, y) +} diff --git a/e2e/e2etests/test_precompiles_bank.go b/e2e/e2etests/test_precompiles_bank.go index 308f684572..db16cc0b75 100644 --- a/e2e/e2etests/test_precompiles_bank.go +++ b/e2e/e2etests/test_precompiles_bank.go @@ -46,6 +46,12 @@ func TestPrecompilesBank(r *runner.E2ERunner, args []string) { utils.RequireTxSuccessful(r, receipt, "Resetting balance failed") }() + // Ensure starting allowance is zero; this is needed when running the tests multiple times + tx, err := r.ERC20ZRC20.Approve(r.ZEVMAuth, bankAddress, big.NewInt(0)) + require.NoError(r, err) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + utils.RequireTxSuccessful(r, receipt, "Resetting allowance failed") + // Get ERC20ZRC20. txHash := r.DepositERC20WithAmountAndMessage(r.EVMAddress(), totalAmount, []byte{}) utils.WaitCctxMinedByInboundHash(r.Ctx, txHash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout) @@ -54,15 +60,18 @@ func TestPrecompilesBank(r *runner.E2ERunner, args []string) { bankContract, err := bank.NewIBank(bank.ContractAddress, r.ZEVMClient) require.NoError(r, err, "Failed to create bank contract caller") - // Cosmos coin balance should be 0 at this point. - cosmosBalance, err := bankContract.BalanceOf(&bind.CallOpts{Context: r.Ctx}, r.ERC20ZRC20Addr, spender) + // get starting balances + startSpenderCosmosBalance, err := bankContract.BalanceOf(&bind.CallOpts{Context: r.Ctx}, r.ERC20ZRC20Addr, spender) require.NoError(r, err, "Call bank.BalanceOf()") - require.Equal(r, uint64(0), cosmosBalance.Uint64(), "spender cosmos coin balance should be 0") + startSpenderZRC20Balance, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{Context: r.Ctx}, spender) + require.NoError(r, err, "Call bank.BalanceOf()") + startBankZRC20Balance, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{Context: r.Ctx}, bankAddress) + require.NoError(r, err, "Call ERC20ZRC20.BalanceOf") // Approve allowance of 500 ERC20ZRC20 tokens for the bank contract. Should pass. - tx, err := r.ERC20ZRC20.Approve(r.ZEVMAuth, bankAddress, depositAmount) + tx, err = r.ERC20ZRC20.Approve(r.ZEVMAuth, bankAddress, depositAmount) require.NoError(r, err) - receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) utils.RequireTxSuccessful(r, receipt, "Approve ETHZRC20 bank allowance tx failed") // Deposit 501 ERC20ZRC20 tokens to the bank contract. @@ -99,17 +108,27 @@ func TestPrecompilesBank(r *runner.E2ERunner, args []string) { require.Equal(r, depositAmount, eventDeposit.Amount, "Deposit event amount should be 500") // Spender: cosmos coin balance should be 500 at this point. - cosmosBalance, err = bankContract.BalanceOf(&bind.CallOpts{Context: r.Ctx}, r.ERC20ZRC20Addr, spender) + spenderCosmosBalance, err := bankContract.BalanceOf(&bind.CallOpts{Context: r.Ctx}, r.ERC20ZRC20Addr, spender) require.NoError(r, err, "Call bank.BalanceOf()") - require.Equal(r, uint64(500), cosmosBalance.Uint64(), "spender cosmos coin balance should be 500") + require.Equal( + r, + startSpenderCosmosBalance.Int64()+500, + spenderCosmosBalance.Int64(), + "spender cosmos coin balance should be +500", + ) // Bank: ERC20ZRC20 balance should be 500 tokens locked. bankZRC20Balance, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{Context: r.Ctx}, bankAddress) require.NoError(r, err, "Call ERC20ZRC20.BalanceOf") - require.Equal(r, uint64(500), bankZRC20Balance.Uint64(), "bank ERC20ZRC20 balance should be 500") + require.Equal( + r, + startBankZRC20Balance.Int64()+500, + bankZRC20Balance.Int64(), + "bank ERC20ZRC20 balance should be +500", + ) - // Try to withdraw 501 ERC20ZRC20 tokens. Should fail. - tx, err = bankContract.Withdraw(r.ZEVMAuth, r.ERC20ZRC20Addr, big.NewInt(501)) + // Try to withdraw one more than current balance. Should fail. + tx, err = bankContract.Withdraw(r.ZEVMAuth, r.ERC20ZRC20Addr, new(big.Int).Add(spenderCosmosBalance, big.NewInt(1))) require.NoError(r, err, "Error calling bank.withdraw()") receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) utils.RequiredTxFailed(r, receipt, "Withdrawing more than cosmos coin balance amount should fail") @@ -118,7 +137,12 @@ func TestPrecompilesBank(r *runner.E2ERunner, args []string) { // No tokens should be unlocked with a failed withdraw. bankZRC20Balance, err = r.ERC20ZRC20.BalanceOf(&bind.CallOpts{Context: r.Ctx}, bankAddress) require.NoError(r, err, "Call ERC20ZRC20.BalanceOf") - require.Equal(r, uint64(500), bankZRC20Balance.Uint64(), "bank ERC20ZRC20 balance should be 500") + require.Equal( + r, + startBankZRC20Balance.Int64()+500, + bankZRC20Balance.Int64(), + "bank ERC20ZRC20 balance should be +500", + ) // Try to withdraw 500 ERC20ZRC20 tokens. Should pass. tx, err = bankContract.Withdraw(r.ZEVMAuth, r.ERC20ZRC20Addr, depositAmount) @@ -133,20 +157,35 @@ func TestPrecompilesBank(r *runner.E2ERunner, args []string) { require.Equal(r, r.ERC20ZRC20Addr, eventWithdraw.Zrc20Token, "Withdraw event token should be ERC20ZRC20Addr") require.Equal(r, depositAmount, eventWithdraw.Amount, "Withdraw event amount should be 500") - // Spender: cosmos coin balance should be 0 at this point. - cosmosBalance, err = bankContract.BalanceOf(&bind.CallOpts{Context: r.Ctx}, r.ERC20ZRC20Addr, spender) + // Spender: cosmos coin balance should be +0 at this point. + spenderCosmosBalance, err = bankContract.BalanceOf(&bind.CallOpts{Context: r.Ctx}, r.ERC20ZRC20Addr, spender) require.NoError(r, err, "Call bank.BalanceOf()") - require.Equal(r, uint64(0), cosmosBalance.Uint64(), "spender cosmos coin balance should be 0") + require.Equal( + r, + startSpenderCosmosBalance.Int64(), + spenderCosmosBalance.Int64(), + "spender cosmos coin balance should match starting balance", + ) - // Spender: ERC20ZRC20 balance should be 1000 at this point. - zrc20Balance, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{Context: r.Ctx}, spender) - require.NoError(r, err, "Call bank.BalanceOf()") - require.Equal(r, uint64(1000), zrc20Balance.Uint64(), "spender ERC20ZRC20 balance should be 1000") + // Spender: ERC20ZRC20 balance should be +0 at this point. + spenderZRC20Balance, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{Context: r.Ctx}, spender) + require.NoError(r, err, "Call ERC20ZRC20.BalanceOf") + require.Equal( + r, + startSpenderZRC20Balance.Int64(), + spenderZRC20Balance.Int64(), + "spender ERC20ZRC20 balance should match starting balance", + ) - // Bank: ERC20ZRC20 balance should be 0 tokens locked. + // Bank: ERC20ZRC20 balance should be +0 tokens locked. bankZRC20Balance, err = r.ERC20ZRC20.BalanceOf(&bind.CallOpts{Context: r.Ctx}, bankAddress) require.NoError(r, err, "Call ERC20ZRC20.BalanceOf") - require.Equal(r, uint64(0), bankZRC20Balance.Uint64(), "bank ERC20ZRC20 balance should be 0") + require.Equal( + r, + startBankZRC20Balance.Int64(), + bankZRC20Balance.Int64(), + "bank ERC20ZRC20 balance should match starting balance", + ) } func TestPrecompilesBankNonZRC20(r *runner.E2ERunner, args []string) { diff --git a/e2e/e2etests/test_precompiles_bank_through_contract.go b/e2e/e2etests/test_precompiles_bank_through_contract.go index 18532f2bd6..01e280b9df 100644 --- a/e2e/e2etests/test_precompiles_bank_through_contract.go +++ b/e2e/e2etests/test_precompiles_bank_through_contract.go @@ -47,7 +47,7 @@ func TestPrecompilesBankThroughContract(r *runner.E2ERunner, args []string) { r.ZEVMAuth.GasLimit = previousGasLimit // Reset the allowance to 0; this is needed when running upgrade tests where this test runs twice. - approveAllowance(r, bank.ContractAddress, big.NewInt(0)) + approveAllowance(r, bank.ContractAddress, zero) // Reset balance to 0; this is needed when running upgrade tests where this test runs twice. tx, err = r.ERC20ZRC20.Transfer( @@ -60,19 +60,22 @@ func TestPrecompilesBankThroughContract(r *runner.E2ERunner, args []string) { utils.RequireTxSuccessful(r, receipt, "Resetting balance failed") }() - // Check initial balances. - balanceShouldBe(r, zero, checkCosmosBalanceThroughBank(r, testBank, zrc20Address, spender)) - balanceShouldBe(r, oneThousand, checkZRC20Balance(r, spender)) - balanceShouldBe(r, zero, checkZRC20Balance(r, bankAddress)) + // always ensure allowance is set to zero before test starts + approveAllowance(r, bank.ContractAddress, zero) + + // get starting balances + startSpenderCosmosBalance := checkCosmosBalanceThroughBank(r, testBank, zrc20Address, spender) + startSpenderZRC20Balance := checkZRC20Balance(r, spender) + startBankZRC20Balance := checkZRC20Balance(r, bankAddress) // Deposit without previous alllowance should fail. receipt = depositThroughTestBank(r, testBank, zrc20Address, oneThousand) utils.RequiredTxFailed(r, receipt, "Deposit ERC20ZRC20 without allowance should fail") // Check balances, should be the same. - balanceShouldBe(r, zero, checkCosmosBalanceThroughBank(r, testBank, zrc20Address, spender)) - balanceShouldBe(r, oneThousand, checkZRC20Balance(r, spender)) - balanceShouldBe(r, zero, checkZRC20Balance(r, bankAddress)) + balanceShouldBe(r, startSpenderCosmosBalance, checkCosmosBalanceThroughBank(r, testBank, zrc20Address, spender)) + balanceShouldBe(r, startSpenderZRC20Balance, checkZRC20Balance(r, spender)) + balanceShouldBe(r, startBankZRC20Balance, checkZRC20Balance(r, bankAddress)) // Allow 500 ZRC20 to bank precompile. approveAllowance(r, bankAddress, fiveHundred) @@ -83,9 +86,9 @@ func TestPrecompilesBankThroughContract(r *runner.E2ERunner, args []string) { utils.RequiredTxFailed(r, receipt, "Depositting an amount higher than allowed should fail") // Balances shouldn't change. - balanceShouldBe(r, zero, checkCosmosBalanceThroughBank(r, testBank, zrc20Address, spender)) - balanceShouldBe(r, oneThousand, checkZRC20Balance(r, spender)) - balanceShouldBe(r, zero, checkZRC20Balance(r, bankAddress)) + balanceShouldBe(r, startSpenderCosmosBalance, checkCosmosBalanceThroughBank(r, testBank, zrc20Address, spender)) + balanceShouldBe(r, startSpenderZRC20Balance, checkZRC20Balance(r, spender)) + balanceShouldBe(r, startBankZRC20Balance, checkZRC20Balance(r, bankAddress)) // Allow 1000 ZRC20 to bank precompile. approveAllowance(r, bankAddress, oneThousand) @@ -96,18 +99,22 @@ func TestPrecompilesBankThroughContract(r *runner.E2ERunner, args []string) { utils.RequiredTxFailed(r, receipt, "Depositting an amount higher than balance should fail") // Balances shouldn't change. - balanceShouldBe(r, zero, checkCosmosBalanceThroughBank(r, testBank, zrc20Address, spender)) - balanceShouldBe(r, oneThousand, checkZRC20Balance(r, spender)) - balanceShouldBe(r, zero, checkZRC20Balance(r, bankAddress)) + balanceShouldBe(r, startSpenderCosmosBalance, checkCosmosBalanceThroughBank(r, testBank, zrc20Address, spender)) + balanceShouldBe(r, startSpenderZRC20Balance, checkZRC20Balance(r, spender)) + balanceShouldBe(r, startBankZRC20Balance, checkZRC20Balance(r, bankAddress)) // Deposit 500 ERC20ZRC20 tokens to the bank contract, it's within allowance and balance. Should pass. receipt = depositThroughTestBank(r, testBank, zrc20Address, fiveHundred) utils.RequireTxSuccessful(r, receipt, "Depositting a correct amount should pass") // Balances should be transferred. Bank now locks 500 ZRC20 tokens. - balanceShouldBe(r, fiveHundred, checkCosmosBalanceThroughBank(r, testBank, zrc20Address, spender)) - balanceShouldBe(r, fiveHundred, checkZRC20Balance(r, spender)) - balanceShouldBe(r, fiveHundred, checkZRC20Balance(r, bankAddress)) + balanceShouldBe( + r, + bigAdd(startSpenderCosmosBalance, fiveHundred), + checkCosmosBalanceThroughBank(r, testBank, zrc20Address, spender), + ) + balanceShouldBe(r, bigSub(startSpenderZRC20Balance, fiveHundred), checkZRC20Balance(r, spender)) + balanceShouldBe(r, bigAdd(startBankZRC20Balance, fiveHundred), checkZRC20Balance(r, bankAddress)) // Check the deposit event. eventDeposit, err := bankPrecompileCaller.ParseDeposit(*receipt.Logs[0]) @@ -117,22 +124,26 @@ func TestPrecompilesBankThroughContract(r *runner.E2ERunner, args []string) { require.Equal(r, fiveHundred, eventDeposit.Amount, "Deposit event amount should be 500") // Should faild to withdraw more than cosmos balance. - receipt = withdrawThroughTestBank(r, testBank, zrc20Address, fiveHundredOne) + receipt = withdrawThroughTestBank(r, testBank, zrc20Address, bigAdd(startSpenderCosmosBalance, fiveHundredOne)) utils.RequiredTxFailed(r, receipt, "Withdrawing an amount higher than balance should fail") // Balances shouldn't change. - balanceShouldBe(r, fiveHundred, checkCosmosBalanceThroughBank(r, testBank, zrc20Address, spender)) - balanceShouldBe(r, fiveHundred, checkZRC20Balance(r, spender)) - balanceShouldBe(r, fiveHundred, checkZRC20Balance(r, bankAddress)) + balanceShouldBe( + r, + bigAdd(startSpenderCosmosBalance, fiveHundred), + checkCosmosBalanceThroughBank(r, testBank, zrc20Address, spender), + ) + balanceShouldBe(r, bigSub(startSpenderZRC20Balance, fiveHundred), checkZRC20Balance(r, spender)) + balanceShouldBe(r, bigAdd(startBankZRC20Balance, fiveHundred), checkZRC20Balance(r, bankAddress)) // Try to withdraw 500 ERC20ZRC20 tokens. Should pass. receipt = withdrawThroughTestBank(r, testBank, zrc20Address, fiveHundred) utils.RequireTxSuccessful(r, receipt, "Withdraw correct amount should pass") // Balances should be reverted to initial state. - balanceShouldBe(r, zero, checkCosmosBalanceThroughBank(r, testBank, zrc20Address, spender)) - balanceShouldBe(r, oneThousand, checkZRC20Balance(r, spender)) - balanceShouldBe(r, zero, checkZRC20Balance(r, bankAddress)) + balanceShouldBe(r, startSpenderCosmosBalance, checkCosmosBalanceThroughBank(r, testBank, zrc20Address, spender)) + balanceShouldBe(r, startSpenderZRC20Balance, checkZRC20Balance(r, spender)) + balanceShouldBe(r, startBankZRC20Balance, checkZRC20Balance(r, bankAddress)) // Check the withdraw event. eventWithdraw, err := bankPrecompileCaller.ParseWithdraw(*receipt.Logs[0])