github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/test/e2e/forced_batches_test.go (about)

     1  package e2e
     2  
     3  import (
     4  	"context"
     5  	"math/big"
     6  	"sync"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/0xPolygon/supernets2-node/etherman/smartcontracts/polygonzkevmglobalexitroot"
    11  	"github.com/0xPolygon/supernets2-node/etherman/smartcontracts/supernets2"
    12  	"github.com/0xPolygon/supernets2-node/log"
    13  	"github.com/0xPolygon/supernets2-node/state"
    14  	"github.com/0xPolygon/supernets2-node/test/constants"
    15  	"github.com/0xPolygon/supernets2-node/test/operations"
    16  	"github.com/ethereum/go-ethereum"
    17  	"github.com/ethereum/go-ethereum/accounts/abi/bind"
    18  	"github.com/ethereum/go-ethereum/common"
    19  	"github.com/ethereum/go-ethereum/core/types"
    20  	"github.com/ethereum/go-ethereum/ethclient"
    21  	"github.com/stretchr/testify/require"
    22  )
    23  
    24  func TestForcedBatches(t *testing.T) {
    25  	if testing.Short() {
    26  		t.Skip()
    27  	}
    28  
    29  	defer func() {
    30  		require.NoError(t, operations.Teardown())
    31  	}()
    32  
    33  	var err error
    34  	nTxs := 10
    35  	ctx := context.Background()
    36  	opsman, auth, client, amount, gasLimit, gasPrice, nonce := setupEnvironment(ctx, t)
    37  
    38  	txs := make([]*types.Transaction, 0, nTxs)
    39  	for i := 0; i < nTxs; i++ {
    40  		tx := types.NewTransaction(nonce, toAddress, amount, gasLimit, gasPrice, nil)
    41  		nonce = nonce + 1
    42  		txs = append(txs, tx)
    43  	}
    44  
    45  	wgNormalL2Transfers := new(sync.WaitGroup)
    46  	wgNormalL2Transfers.Add(1)
    47  	var l2BlockNumbers []*big.Int
    48  	go func() {
    49  		defer wgNormalL2Transfers.Done()
    50  		l2BlockNumbers, err = operations.ApplyL2Txs(ctx, txs, auth, client, operations.VerifiedConfirmationLevel)
    51  		require.NoError(t, err)
    52  	}()
    53  
    54  	time.Sleep(2 * time.Second)
    55  	amount = big.NewInt(0).Add(amount, big.NewInt(10))
    56  	unsignedTx := types.NewTransaction(nonce, toAddress, amount, gasLimit, gasPrice, nil)
    57  	signedTx, err := auth.Signer(auth.From, unsignedTx)
    58  	require.NoError(t, err)
    59  	encodedTxs, err := state.EncodeTransactions([]types.Transaction{*signedTx})
    60  	require.NoError(t, err)
    61  	forcedBatch, err := sendForcedBatch(t, encodedTxs, opsman)
    62  	require.NoError(t, err)
    63  
    64  	// Checking if all txs sent before the forced batch were processed within previous closed batch
    65  	wgNormalL2Transfers.Wait()
    66  	for _, l2blockNum := range l2BlockNumbers {
    67  		batch, err := opsman.State().GetBatchByL2BlockNumber(ctx, l2blockNum.Uint64(), nil)
    68  		require.NoError(t, err)
    69  		require.Less(t, batch.BatchNumber, forcedBatch.BatchNumber)
    70  	}
    71  }
    72  
    73  func setupEnvironment(ctx context.Context, t *testing.T) (*operations.Manager, *bind.TransactOpts, *ethclient.Client, *big.Int, uint64, *big.Int, uint64) {
    74  
    75  	err := operations.Teardown()
    76  	require.NoError(t, err)
    77  	opsCfg := operations.GetDefaultOperationsConfig()
    78  	opsCfg.State.MaxCumulativeGasUsed = 80000000000
    79  	opsman, err := operations.NewManager(ctx, opsCfg)
    80  	require.NoError(t, err)
    81  	err = opsman.Setup()
    82  	require.NoError(t, err)
    83  	time.Sleep(5 * time.Second)
    84  	// Load account with balance on local genesis
    85  	auth, err := operations.GetAuth(operations.DefaultSequencerPrivateKey, operations.DefaultL2ChainID)
    86  	require.NoError(t, err)
    87  	// Load eth client
    88  	client, err := ethclient.Dial(operations.DefaultL2NetworkURL)
    89  	require.NoError(t, err)
    90  	// Send txs
    91  	amount := big.NewInt(10000)
    92  	senderBalance, err := client.BalanceAt(ctx, auth.From, nil)
    93  	require.NoError(t, err)
    94  	senderNonce, err := client.PendingNonceAt(ctx, auth.From)
    95  	require.NoError(t, err)
    96  
    97  	log.Infof("Receiver Addr: %v", toAddress.String())
    98  	log.Infof("Sender Addr: %v", auth.From.String())
    99  	log.Infof("Sender Balance: %v", senderBalance.String())
   100  	log.Infof("Sender Nonce: %v", senderNonce)
   101  
   102  	gasLimit, err := client.EstimateGas(ctx, ethereum.CallMsg{From: auth.From, To: &toAddress, Value: amount})
   103  	require.NoError(t, err)
   104  
   105  	gasPrice, err := client.SuggestGasPrice(ctx)
   106  	require.NoError(t, err)
   107  
   108  	nonce, err := client.PendingNonceAt(ctx, auth.From)
   109  	require.NoError(t, err)
   110  	return opsman, auth, client, amount, gasLimit, gasPrice, nonce
   111  }
   112  
   113  func sendForcedBatch(t *testing.T, txs []byte, opsman *operations.Manager) (*state.Batch, error) {
   114  	ctx := context.Background()
   115  	st := opsman.State()
   116  	// Connect to ethereum node
   117  	ethClient, err := ethclient.Dial(operations.DefaultL1NetworkURL)
   118  	require.NoError(t, err)
   119  
   120  	initialGer, _, err := st.GetLatestGer(ctx, gerFinalityBlocks)
   121  	require.NoError(t, err)
   122  
   123  	// Create smc client
   124  	zkEvmAddr := common.HexToAddress(operations.DefaultL1Supernets2SmartContract)
   125  	zkEvm, err := supernets2.NewSupernets2(zkEvmAddr, ethClient)
   126  	require.NoError(t, err)
   127  
   128  	auth, err := operations.GetAuth(operations.DefaultSequencerPrivateKey, operations.DefaultL1ChainID)
   129  	require.NoError(t, err)
   130  
   131  	log.Info("Using address: ", auth.From)
   132  
   133  	num, err := zkEvm.LastForceBatch(&bind.CallOpts{Pending: false})
   134  	require.NoError(t, err)
   135  
   136  	log.Info("Number of forceBatches in the smc: ", num)
   137  
   138  	// Get tip
   139  	tip, err := zkEvm.GetForcedBatchFee(&bind.CallOpts{Pending: false})
   140  	require.NoError(t, err)
   141  
   142  	managerAddress, err := zkEvm.GlobalExitRootManager(&bind.CallOpts{Pending: false})
   143  	require.NoError(t, err)
   144  
   145  	manager, err := polygonzkevmglobalexitroot.NewPolygonzkevmglobalexitroot(managerAddress, ethClient)
   146  	require.NoError(t, err)
   147  
   148  	rootInContract, err := manager.GetLastGlobalExitRoot(&bind.CallOpts{Pending: false})
   149  	require.NoError(t, err)
   150  	rootInContractHash := common.BytesToHash(rootInContract[:])
   151  
   152  	disallowed, err := zkEvm.IsForcedBatchDisallowed(&bind.CallOpts{Pending: false})
   153  	require.NoError(t, err)
   154  	if disallowed {
   155  		tx, err := zkEvm.ActivateForceBatches(auth)
   156  		require.NoError(t, err)
   157  		err = operations.WaitTxToBeMined(ctx, ethClient, tx, operations.DefaultTimeoutTxToBeMined)
   158  		require.NoError(t, err)
   159  	}
   160  
   161  	currentBlock, err := ethClient.BlockByNumber(ctx, nil)
   162  	require.NoError(t, err)
   163  
   164  	log.Debug("currentBlock.Time(): ", currentBlock.Time())
   165  
   166  	// Send forceBatch
   167  	tx, err := zkEvm.ForceBatch(auth, txs, tip)
   168  	require.NoError(t, err)
   169  
   170  	log.Info("TxHash: ", tx.Hash())
   171  	time.Sleep(1 * time.Second)
   172  
   173  	err = operations.WaitTxToBeMined(ctx, ethClient, tx, operations.DefaultTimeoutTxToBeMined)
   174  	require.NoError(t, err)
   175  
   176  	query := ethereum.FilterQuery{
   177  		FromBlock: currentBlock.Number(),
   178  		Addresses: []common.Address{zkEvmAddr},
   179  	}
   180  	logs, err := ethClient.FilterLogs(ctx, query)
   181  	require.NoError(t, err)
   182  
   183  	var forcedBatch *state.Batch
   184  	for _, vLog := range logs {
   185  		if vLog.Topics[0] != constants.ForcedBatchSignatureHash {
   186  			logs, err = ethClient.FilterLogs(ctx, query)
   187  			require.NoError(t, err)
   188  			continue
   189  		}
   190  		fb, err := zkEvm.ParseForceBatch(vLog)
   191  		if err != nil {
   192  			log.Errorf("failed to parse force batch log event, err: ", err)
   193  		}
   194  		log.Debugf("log decoded: %+v", fb)
   195  		ger := fb.LastGlobalExitRoot
   196  		log.Info("GlobalExitRoot: ", ger)
   197  		log.Info("Transactions: ", common.Bytes2Hex(fb.Transactions))
   198  		fullBlock, err := ethClient.BlockByHash(ctx, vLog.BlockHash)
   199  		if err != nil {
   200  			log.Errorf("error getting hashParent. BlockNumber: %d. Error: %v", vLog.BlockNumber, err)
   201  			return nil, err
   202  		}
   203  		log.Info("MinForcedTimestamp: ", fullBlock.Time())
   204  		forcedBatch, err = st.GetBatchByForcedBatchNum(ctx, fb.ForceBatchNum, nil)
   205  		for err == state.ErrStateNotSynchronized {
   206  			time.Sleep(1 * time.Second)
   207  			forcedBatch, err = st.GetBatchByForcedBatchNum(ctx, fb.ForceBatchNum, nil)
   208  		}
   209  		log.Info("ForcedBatchNum: ", forcedBatch.BatchNumber)
   210  		require.NoError(t, err)
   211  		require.NotNil(t, forcedBatch)
   212  
   213  		log.Info("Waiting for batch to be virtualized...")
   214  		err = operations.WaitBatchToBeVirtualized(forcedBatch.BatchNumber, 4*time.Minute, st)
   215  		require.NoError(t, err)
   216  
   217  		log.Info("Waiting for batch to be consolidated...")
   218  		err = operations.WaitBatchToBeConsolidated(forcedBatch.BatchNumber, 4*time.Minute, st)
   219  		require.NoError(t, err)
   220  
   221  		if rootInContractHash != initialGer.GlobalExitRoot {
   222  			finalGer, _, err := st.GetLatestGer(ctx, gerFinalityBlocks)
   223  			require.NoError(t, err)
   224  			if finalGer.GlobalExitRoot != rootInContractHash {
   225  				log.Fatal("global exit root is not updated")
   226  			}
   227  		}
   228  	}
   229  
   230  	return forcedBatch, nil
   231  }