Skip to content

Commit

Permalink
E2E test native tokens bridge more than 0x0 balance (#253)
Browse files Browse the repository at this point in the history
* Implement e2e test

* Rename test and add comment

* Linters fix

* Shorten test execution

* Extract logs count to a constant
  • Loading branch information
Stefan-Ethernal authored May 28, 2024
1 parent 4ac5d03 commit 0a412e3
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 13 deletions.
71 changes: 60 additions & 11 deletions e2e-polybft/e2e/bridge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func TestE2E_Bridge_RootchainTokensTransfers(t *testing.T) {

// assert that all deposits are executed successfully
// because of the token mapping with the first deposit
checkStateSyncResultLogs(t, logs, transfersCount+1)
assertStateSyncResultSuccess(t, logs, transfersCount+1)

// get child token address
childERC20Token := getChildToken(t, contractsapi.RootERC20Predicate.Abi,
Expand Down Expand Up @@ -282,7 +282,7 @@ func TestE2E_Bridge_RootchainTokensTransfers(t *testing.T) {
require.NoError(t, err)

// assert that all state syncs are executed successfully
checkStateSyncResultLogs(t, logs, transfersCount)
assertStateSyncResultSuccess(t, logs, transfersCount)
})
}

Expand Down Expand Up @@ -384,7 +384,7 @@ func TestE2E_Bridge_ERC721Transfer(t *testing.T) {
// assert that all deposits are executed successfully.
// All deposits are sent using a single transaction, so arbitrary message bridge emits two state sync events:
// MAP_TOKEN_SIG and DEPOSIT_BATCH_SIG state sync events
checkStateSyncResultLogs(t, logs, stateSyncedLogsCount)
assertStateSyncResultSuccess(t, logs, stateSyncedLogsCount)

break
}
Expand Down Expand Up @@ -558,7 +558,7 @@ func TestE2E_Bridge_ERC1155Transfer(t *testing.T) {
// assert that all deposits are executed successfully.
// All deposits are sent using a single transaction, so arbitrary message bridge emits two state sync events:
// MAP_TOKEN_SIG and DEPOSIT_BATCH_SIG state sync events
checkStateSyncResultLogs(t, logs, stateSyncedLogsCount)
assertStateSyncResultSuccess(t, logs, stateSyncedLogsCount)

break
}
Expand Down Expand Up @@ -1146,7 +1146,7 @@ func TestE2E_Bridge_Transfers_AccessLists(t *testing.T) {

// assert that all deposits are executed successfully
// (token mapping and transferCount of deposits)
checkStateSyncResultLogs(t, logs, transfersCount+1)
assertStateSyncResultSuccess(t, logs, transfersCount+1)

// get child token address
childERC20Token := getChildToken(t, contractsapi.RootERC20Predicate.Abi,
Expand Down Expand Up @@ -1256,6 +1256,7 @@ func TestE2E_Bridge_NonMintableERC20Token_WithPremine(t *testing.T) {
numBlockConfirmations = uint64(2)
exitEventsCount = uint64(2)
tokensToTransfer = ethgo.Gwei(10)
tenMilionTokens = ethgo.Ether(10000000)
bigZero = big.NewInt(0)
)

Expand Down Expand Up @@ -1290,7 +1291,7 @@ func TestE2E_Bridge_NonMintableERC20Token_WithPremine(t *testing.T) {
tcc.Premine = append(tcc.Premine,
fmt.Sprintf("%s:%s:%s",
nonValidatorKey.Address(),
command.DefaultPremineBalance.String(),
new(big.Int).Mul(big.NewInt(10), tenMilionTokens).String(),
nonValidatorKeyString))

// do premine to reward wallet address
Expand All @@ -1301,14 +1302,13 @@ func TestE2E_Bridge_NonMintableERC20Token_WithPremine(t *testing.T) {
rewardWalletKeyString))
}),
)
defer cluster.Stop()

rootchainTxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr()))
require.NoError(t, err)

childEthEndpoint := cluster.Servers[0].JSONRPC()

defer cluster.Stop()

cluster.WaitForReady(t)

polybftCfg, err := polybft.LoadPolyBFTConfig(path.Join(cluster.Config.TmpDir, chainConfigFileName))
Expand Down Expand Up @@ -1354,7 +1354,7 @@ func TestE2E_Bridge_NonMintableERC20Token_WithPremine(t *testing.T) {
})

// this test case will check first if they can withdraw some of the premined amount of non-mintable token
t.Run("Do a withdraw for premined validator address and premined non-validator address", func(t *testing.T) {
t.Run("do a withdraw for premined validator address and premined non-validator address", func(t *testing.T) {
validatorSrv := cluster.Servers[1]
validatorAcc, err := validatorHelper.GetAccountFromDir(validatorSrv.DataDir())
require.NoError(t, err)
Expand Down Expand Up @@ -1422,7 +1422,7 @@ func TestE2E_Bridge_NonMintableERC20Token_WithPremine(t *testing.T) {
checkBalancesFn(types.Address(nonValidatorKey.Address()), tokensToTransfer, nonValidatorBalanceAfterWithdraw, false)
})

t.Run("Do a deposit to some validator and non-validator address", func(t *testing.T) {
t.Run("do a deposit to some validator and non-validator address", func(t *testing.T) {
validatorSrv := cluster.Servers[4]
validatorAcc, err := validatorHelper.GetAccountFromDir(validatorSrv.DataDir())
require.NoError(t, err)
Expand Down Expand Up @@ -1456,7 +1456,56 @@ func TestE2E_Bridge_NonMintableERC20Token_WithPremine(t *testing.T) {

if len(logs) == stateSyncedLogsCount || i == numberOfAttempts-1 {
// assert that all deposits are executed successfully
checkStateSyncResultLogs(t, logs, stateSyncedLogsCount)
assertStateSyncResultSuccess(t, logs, stateSyncedLogsCount)

break
}

require.NoError(t, cluster.WaitForBlock(finalBlockNum+(i+1)*epochSize, time.Minute))
}
})

t.Run("transfer more native tokens than 0x0 balance is", func(t *testing.T) {
const expectedStateSyncsCount = 1

// since bridging native token is essentially minting
// (i.e. transferring tokens from 0x0 to receiver address using native transfer precompile),
// this test tries to deposit more tokens than 0x0 address has on its balance
currentBlock, err := childEthEndpoint.GetBlockByNumber(jsonrpc.LatestBlockNumber, false)
require.NoError(t, err)

require.NoError(t, cluster.Bridge.Deposit(
common.ERC20,
polybftCfg.Bridge.RootNativeERC20Addr,
polybftCfg.Bridge.RootERC20PredicateAddr,
bridgeHelper.TestAccountPrivKey,
strings.Join([]string{nonValidatorKey.Address().String()}, ","),
strings.Join([]string{tenMilionTokens.String()}, ","),
"",
cluster.Bridge.JSONRPCAddr(),
bridgeHelper.TestAccountPrivKey,
false),
)

// wait for couple of epoches
finalBlockNum := currentBlock.Header.Number + epochSize
require.NoError(t, cluster.WaitForBlock(finalBlockNum, 2*time.Minute))

// the transaction is processed and there should be a success event
var stateSyncedResult contractsapi.StateSyncResultEvent

for i := uint64(0); i < numberOfAttempts; i++ {
logs, err := getFilteredLogs(stateSyncedResult.Sig(), currentBlock.Number()+1, finalBlockNum+i*epochSize, childEthEndpoint)
require.NoError(t, err)

if len(logs) == expectedStateSyncsCount || i == numberOfAttempts-1 {
// assert that sent deposit has failed
checkStateSyncResultLogs(t, logs, expectedStateSyncsCount,
func(t *testing.T, ssre contractsapi.StateSyncResultEvent) {
t.Helper()

require.False(t, ssre.Status)
})

break
}
Expand Down
27 changes: 25 additions & 2 deletions e2e-polybft/e2e/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import (

const nativeTokenNonMintableConfig = "Blade:BLD:18:false"

var (
stateSyncResultEvent contractsapi.StateSyncResultEvent
)

func ABICall(relayer txrelayer.TxRelayer, artifact *contracts.Artifact, contractAddress types.Address, senderAddr types.Address, method string, params ...interface{}) (string, error) {
input, err := artifact.Abi.GetMethod(method).Encode(params)
if err != nil {
Expand Down Expand Up @@ -59,22 +63,41 @@ func checkStateSyncResultLogs(
t *testing.T,
logs []*ethgo.Log,
expectedCount int,
handler func(*testing.T, contractsapi.StateSyncResultEvent),
) {
t.Helper()
require.Equal(t, expectedCount, len(logs))

var stateSyncResultEvent contractsapi.StateSyncResultEvent
for _, log := range logs {
doesMatch, err := stateSyncResultEvent.ParseLog(log)
require.NoError(t, err)
require.True(t, doesMatch)

t.Logf("Block Number=%d, Decoded Log=%+v\n", log.BlockNumber, stateSyncResultEvent)

require.True(t, stateSyncResultEvent.Status)
if handler != nil {
handler(t, stateSyncResultEvent)
}
}
}

// assertStateSyncResultSuccess asserts that:
// 1. there are required amount of logs,
// 2. they are of contractsapi.StateSyncResult type
// 3. status is true, meaning that the state syncs were executed successfully
func assertStateSyncResultSuccess(
t *testing.T,
logs []*ethgo.Log,
expectedCount int) {
t.Helper()
checkStateSyncResultLogs(t, logs, expectedCount,
func(t *testing.T, ssre contractsapi.StateSyncResultEvent) {
t.Helper()

require.True(t, ssre.Status)
})
}

// getCheckpointBlockNumber gets current checkpoint block number from checkpoint manager smart contract
func getCheckpointBlockNumber(l1Relayer txrelayer.TxRelayer, checkpointManagerAddr types.Address) (uint64, error) {
checkpointBlockNumRaw, err := ABICall(l1Relayer, contractsapi.CheckpointManager,
Expand Down

0 comments on commit 0a412e3

Please sign in to comment.