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 }