Skip to content

Commit

Permalink
chore(e2e): tolerate multiple runs of precompile tests (#3256)
Browse files Browse the repository at this point in the history
  • Loading branch information
gartnera authored Dec 9, 2024
1 parent 7241601 commit 1329066
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 50 deletions.
24 changes: 18 additions & 6 deletions cmd/zetae2e/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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))
}

Expand All @@ -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()
Expand Down Expand Up @@ -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)")
}
}

Expand Down
10 changes: 10 additions & 0 deletions e2e/e2etests/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
79 changes: 59 additions & 20 deletions e2e/e2etests/test_precompiles_bank.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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.
Expand Down Expand Up @@ -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")
Expand All @@ -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)
Expand All @@ -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) {
Expand Down
59 changes: 35 additions & 24 deletions e2e/e2etests/test_precompiles_bank_through_contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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])
Expand All @@ -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])
Expand Down

0 comments on commit 1329066

Please sign in to comment.