github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/sequencer/finalizer_test.go (about)

     1  package sequencer
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math/big"
     7  	"sync"
     8  	"testing"
     9  	"time"
    10  
    11  	cfgTypes "github.com/0xPolygon/supernets2-node/config/types"
    12  	"github.com/0xPolygon/supernets2-node/event"
    13  	"github.com/0xPolygon/supernets2-node/event/nileventstorage"
    14  	"github.com/0xPolygon/supernets2-node/pool"
    15  	"github.com/0xPolygon/supernets2-node/state"
    16  	"github.com/0xPolygon/supernets2-node/state/runtime/executor"
    17  	"github.com/0xPolygon/supernets2-node/state/runtime/executor/pb"
    18  	"github.com/ethereum/go-ethereum/common"
    19  	"github.com/ethereum/go-ethereum/core/types"
    20  	"github.com/stretchr/testify/assert"
    21  	"github.com/stretchr/testify/mock"
    22  	"github.com/stretchr/testify/require"
    23  )
    24  
    25  var (
    26  	f             *finalizer
    27  	nilErr        error
    28  	dbManagerMock = new(DbManagerMock)
    29  	executorMock  = new(StateMock)
    30  	workerMock    = new(WorkerMock)
    31  	dbTxMock      = new(DbTxMock)
    32  	bc            = batchConstraints{
    33  		MaxTxsPerBatch:       150,
    34  		MaxBatchBytesSize:    129848,
    35  		MaxCumulativeGasUsed: 30000000,
    36  		MaxKeccakHashes:      468,
    37  		MaxPoseidonHashes:    279620,
    38  		MaxPoseidonPaddings:  149796,
    39  		MaxMemAligns:         262144,
    40  		MaxArithmetics:       262144,
    41  		MaxBinaries:          262144,
    42  		MaxSteps:             8388608,
    43  	}
    44  	txsStore = TxsStore{
    45  		Ch: make(chan *txToStore, 1),
    46  		Wg: new(sync.WaitGroup),
    47  	}
    48  	closingSignalCh = ClosingSignalCh{
    49  		ForcedBatchCh: make(chan state.ForcedBatch),
    50  		GERCh:         make(chan common.Hash),
    51  		L2ReorgCh:     make(chan L2ReorgEvent),
    52  	}
    53  	cfg = FinalizerCfg{
    54  		GERDeadlineTimeout: cfgTypes.Duration{
    55  			Duration: 60,
    56  		},
    57  		ForcedBatchDeadlineTimeout: cfgTypes.Duration{
    58  			Duration: 60,
    59  		},
    60  		SleepDuration: cfgTypes.Duration{
    61  			Duration: 60,
    62  		},
    63  		ClosingSignalsManagerWaitForCheckingL1Timeout: cfgTypes.Duration{
    64  			Duration: 10 * time.Second,
    65  		},
    66  		ClosingSignalsManagerWaitForCheckingGER: cfgTypes.Duration{
    67  			Duration: 10 * time.Second,
    68  		},
    69  		ClosingSignalsManagerWaitForCheckingForcedBatches: cfgTypes.Duration{
    70  			Duration: 10 * time.Second,
    71  		},
    72  		ResourcePercentageToCloseBatch: 10,
    73  		GERFinalityNumberOfBlocks:      64,
    74  	}
    75  	seqAddr  = common.Address{}
    76  	oldHash  = common.HexToHash("0x29e885edaf8e4b51e1d2e05f9da28161d2fb4f6b1d53827d9b80a23cf2d7d9f2")
    77  	newHash  = common.HexToHash("0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
    78  	sender   = common.HexToAddress("0x3445324")
    79  	isSynced = func(ctx context.Context) bool {
    80  		return true
    81  	}
    82  	// tx1 = ethTypes.NewTransaction(0, common.HexToAddress("0"), big.NewInt(0), 0, big.NewInt(0), []byte("aaa"))
    83  	// tx2 = ethTypes.NewTransaction(1, common.HexToAddress("1"), big.NewInt(1), 0, big.NewInt(1), []byte("bbb"))
    84  
    85  	testErr = fmt.Errorf("some error")
    86  	// testErr2         = fmt.Errorf("some error2")
    87  	openBatchError   = fmt.Errorf("failed to open new batch, err: %w", testErr)
    88  	cumulativeGasErr = state.GetZKCounterError("CumulativeGasUsed")
    89  )
    90  
    91  func testNow() time.Time {
    92  	return time.Unix(0, 0)
    93  }
    94  
    95  func TestNewFinalizer(t *testing.T) {
    96  	eventStorage, err := nileventstorage.NewNilEventStorage()
    97  	require.NoError(t, err)
    98  	eventLog := event.NewEventLog(event.Config{}, eventStorage)
    99  
   100  	// arrange and act
   101  	f = newFinalizer(cfg, workerMock, dbManagerMock, executorMock, seqAddr, isSynced, closingSignalCh, txsStore, bc, eventLog)
   102  
   103  	// assert
   104  	assert.NotNil(t, f)
   105  	assert.Equal(t, f.cfg, cfg)
   106  	assert.Equal(t, f.worker, workerMock)
   107  	assert.Equal(t, f.dbManager, dbManagerMock)
   108  	assert.Equal(t, f.executor, executorMock)
   109  	assert.Equal(t, f.sequencerAddress, seqAddr)
   110  	assert.Equal(t, f.closingSignalCh, closingSignalCh)
   111  	assert.Equal(t, f.txsStore, txsStore)
   112  	assert.Equal(t, f.batchConstraints, bc)
   113  }
   114  
   115  //
   116  //func TestFinalizer_newWIPBatch(t *testing.T) {
   117  //	// arrange
   118  //	f = setupFinalizer(true)
   119  //	now = testNow
   120  //	defer func() {
   121  //		now = time.Now
   122  //	}()
   123  //
   124  //	txs := make([]types.Transaction, 0)
   125  //	batchNum := f.batch.batchNumber + 1
   126  //	f.processRequest.GlobalExitRoot = oldHash
   127  //	f.processRequest.OldStateRoot = oldHash
   128  //	f.processRequest.Transactions = []byte{}
   129  //	expectedWipBatch := &WipBatch{
   130  //		batchNumber:        batchNum,
   131  //		coinbase:           f.sequencerAddress,
   132  //		initialStateRoot:   newHash,
   133  //		stateRoot:          newHash,
   134  //		timestamp:          uint64(now().Unix()),
   135  //		remainingResources: getMaxRemainingResources(f.batchConstraints),
   136  //	}
   137  //	closeBatchParams := ClosingBatchParameters{
   138  //		BatchNumber:   f.batch.batchNumber,
   139  //		StateRoot:     f.batch.stateRoot,
   140  //		LocalExitRoot: f.batch.localExitRoot,
   141  //		Txs:           txs,
   142  //	}
   143  //	batches := []*state.Batch{
   144  //		{
   145  //			BatchNumber: 0,
   146  //			StateRoot:   oldHash,
   147  //		},
   148  //	}
   149  //	testCases := []struct {
   150  //		name             string
   151  //		batches          []*state.Batch
   152  //		closeBatchErr    error
   153  //		closeBatchParams ClosingBatchParameters
   154  //		openBatchErr     error
   155  //		expectedWip      *WipBatch
   156  //		expectedErr      error
   157  //	}{
   158  //		{
   159  //			name:             "Success",
   160  //			expectedWip:      expectedWipBatch,
   161  //			closeBatchParams: closeBatchParams,
   162  //			batches:          batches,
   163  //		},
   164  //		{
   165  //			name:             "Close Batch Error",
   166  //			expectedWip:      expectedWipBatch,
   167  //			closeBatchParams: closeBatchParams,
   168  //			batches:          batches,
   169  //			closeBatchErr:    testErr,
   170  //			expectedErr:      fmt.Errorf("failed to close batch, err: %w", testErr),
   171  //		},
   172  //		{
   173  //			name:             "Open Batch Error",
   174  //			expectedWip:      expectedWipBatch,
   175  //			closeBatchParams: closeBatchParams,
   176  //			batches:          batches,
   177  //			openBatchErr:     testErr,
   178  //			expectedErr:      fmt.Errorf("failed to open new batch, err: %w", testErr),
   179  //		},
   180  //	}
   181  //	for _, tc := range testCases {
   182  //		t.Run(tc.name, func(t *testing.T) {
   183  //			// arrange
   184  //			dbManagerMock.On("CloseBatch", ctx, tc.closeBatchParams).Return(tc.closeBatchErr).Once()
   185  //			executorMock.On("ProcessBatch", ctx, f.processRequest).Return(&state.ProcessBatchResponse{
   186  //				IsBatchProcessed: true,
   187  //			}, nilErr).Once()
   188  //
   189  //			if tc.expectedErr == nil {
   190  //				dbManagerMock.On("GetTransactionsByBatchNumber", ctx, f.batch.batchNumber).Return(txs, nilErr).Once()
   191  //			}
   192  //
   193  //			if tc.closeBatchErr == nil {
   194  //				dbManagerMock.On("BeginStateTransaction", ctx).Return(dbTxMock, nilErr).Once()
   195  //				dbManagerMock.On("OpenBatch", ctx, mock.Anything, dbTxMock).Return(tc.openBatchErr).Once()
   196  //
   197  //				// Async Calls from reprocessBatch
   198  //				dbManagerMock.On("GetLastNBatches", ctx, uint(2)).Return(tc.batches, nilErr).Maybe()
   199  //				dbManagerMock.On("GetTransactionsByBatchNumber", ctx, f.batch.batchNumber).Return(txs, nilErr).Maybe()
   200  //				processRequest := f.processRequest
   201  //				processRequest.Caller = state.DiscardCallerLabel
   202  //				processRequest.Timestamp = f.batch.timestamp
   203  //				executorMock.On("ProcessBatch", ctx, processRequest).Return(&state.ProcessBatchResponse{
   204  //					NewStateRoot:     f.batch.stateRoot,
   205  //					NewLocalExitRoot: f.batch.localExitRoot,
   206  //
   207  //					IsBatchProcessed: true,
   208  //				}, nilErr).Maybe()
   209  //
   210  //				if tc.openBatchErr == nil {
   211  //					dbTxMock.On("Commit", ctx).Return(nilErr).Once()
   212  //				} else {
   213  //					dbTxMock.On("Rollback", ctx).Return(nilErr).Once()
   214  //				}
   215  //			}
   216  //
   217  //			// act
   218  //			wipBatch, err := f.newWIPBatch(ctx)
   219  //
   220  //			// assert
   221  //			if tc.expectedErr != nil {
   222  //				assert.Error(t, err)
   223  //				assert.EqualError(t, err, tc.expectedErr.Error())
   224  //				assert.Nil(t, wipBatch)
   225  //			} else {
   226  //				assert.NoError(t, err)
   227  //				assert.Equal(t, tc.expectedWip, wipBatch)
   228  //			}
   229  //			dbManagerMock.AssertExpectations(t)
   230  //			dbTxMock.AssertExpectations(t)
   231  //		})
   232  //	}
   233  //}
   234  
   235  func TestFinalizer_syncWithState(t *testing.T) {
   236  	// arrange
   237  	f = setupFinalizer(true)
   238  	now = testNow
   239  	defer func() {
   240  		now = time.Now
   241  	}()
   242  	one := uint64(1)
   243  	batches := []*state.Batch{
   244  		{
   245  			BatchNumber:    1,
   246  			StateRoot:      oldHash,
   247  			GlobalExitRoot: oldHash,
   248  		},
   249  	}
   250  	testCases := []struct {
   251  		name                  string
   252  		batches               []*state.Batch
   253  		lastBatchNum          *uint64
   254  		isBatchClosed         bool
   255  		ger                   common.Hash
   256  		getWIPBatchErr        error
   257  		openBatchErr          error
   258  		isBatchClosedErr      error
   259  		getLastBatchErr       error
   260  		expectedProcessingCtx state.ProcessingContext
   261  		expectedBatch         *WipBatch
   262  		expectedErr           error
   263  	}{
   264  		{
   265  			name:          "Success-Closed Batch",
   266  			lastBatchNum:  &one,
   267  			isBatchClosed: true,
   268  			ger:           oldHash,
   269  			batches:       batches,
   270  			expectedBatch: &WipBatch{
   271  				batchNumber:        one + 1,
   272  				coinbase:           f.sequencerAddress,
   273  				initialStateRoot:   oldHash,
   274  				stateRoot:          oldHash,
   275  				timestamp:          testNow(),
   276  				globalExitRoot:     oldHash,
   277  				remainingResources: getMaxRemainingResources(f.batchConstraints),
   278  			},
   279  			expectedProcessingCtx: state.ProcessingContext{
   280  				BatchNumber:    one + 1,
   281  				Coinbase:       f.sequencerAddress,
   282  				Timestamp:      testNow(),
   283  				GlobalExitRoot: oldHash,
   284  			},
   285  			expectedErr: nil,
   286  		},
   287  		{
   288  			name:          "Success-Open Batch",
   289  			lastBatchNum:  &one,
   290  			isBatchClosed: false,
   291  			batches:       batches,
   292  			ger:           common.Hash{},
   293  			expectedBatch: &WipBatch{
   294  				batchNumber:        one,
   295  				coinbase:           f.sequencerAddress,
   296  				initialStateRoot:   oldHash,
   297  				stateRoot:          oldHash,
   298  				timestamp:          testNow(),
   299  				globalExitRoot:     oldHash,
   300  				remainingResources: getMaxRemainingResources(f.batchConstraints),
   301  			},
   302  			expectedProcessingCtx: state.ProcessingContext{
   303  				BatchNumber:    one,
   304  				Coinbase:       f.sequencerAddress,
   305  				Timestamp:      testNow(),
   306  				GlobalExitRoot: oldHash,
   307  			},
   308  		},
   309  		{
   310  			name:            "Error-Failed to get last batch",
   311  			lastBatchNum:    nil,
   312  			batches:         batches,
   313  			isBatchClosed:   true,
   314  			ger:             oldHash,
   315  			getLastBatchErr: testErr,
   316  			expectedErr:     fmt.Errorf("failed to get last batch, err: %w", testErr),
   317  		},
   318  		{
   319  			name:             "Error-Failed to check if batch is closed",
   320  			lastBatchNum:     &one,
   321  			batches:          batches,
   322  			isBatchClosed:    true,
   323  			ger:              oldHash,
   324  			isBatchClosedErr: testErr,
   325  			expectedErr:      fmt.Errorf("failed to check if batch is closed, err: %w", testErr),
   326  		},
   327  		{
   328  			name:           "Error-Failed to get work-in-progress batch",
   329  			lastBatchNum:   &one,
   330  			batches:        batches,
   331  			isBatchClosed:  false,
   332  			ger:            common.Hash{},
   333  			getWIPBatchErr: testErr,
   334  			expectedErr:    fmt.Errorf("failed to get work-in-progress batch, err: %w", testErr),
   335  		},
   336  		{
   337  			name:          "Error-Failed to open new batch",
   338  			lastBatchNum:  &one,
   339  			batches:       batches,
   340  			isBatchClosed: true,
   341  			ger:           oldHash,
   342  			openBatchErr:  testErr,
   343  			expectedProcessingCtx: state.ProcessingContext{
   344  				BatchNumber:    one + 1,
   345  				Coinbase:       f.sequencerAddress,
   346  				Timestamp:      testNow(),
   347  				GlobalExitRoot: oldHash,
   348  			},
   349  			expectedErr: fmt.Errorf("failed to open new batch, err: %w", testErr),
   350  		},
   351  	}
   352  
   353  	for _, tc := range testCases {
   354  		t.Run(tc.name, func(t *testing.T) {
   355  			// arrange
   356  			if tc.lastBatchNum == nil {
   357  				dbManagerMock.Mock.On("GetLastBatch", ctx).Return(tc.batches[0], tc.getLastBatchErr).Once()
   358  			} else {
   359  				dbManagerMock.On("GetBatchByNumber", ctx, *tc.lastBatchNum, nil).Return(tc.batches[0], nilErr).Once()
   360  			}
   361  
   362  			if tc.getLastBatchErr == nil {
   363  				dbManagerMock.Mock.On("IsBatchClosed", ctx, *tc.lastBatchNum).Return(tc.isBatchClosed, tc.isBatchClosedErr).Once()
   364  			}
   365  
   366  			if tc.isBatchClosed {
   367  				if tc.getLastBatchErr == nil && tc.isBatchClosedErr == nil {
   368  					dbManagerMock.On("OpenBatch", ctx, tc.expectedProcessingCtx, dbTxMock).Return(tc.openBatchErr).Once()
   369  				}
   370  
   371  				if tc.getLastBatchErr == nil && tc.isBatchClosedErr == nil {
   372  					dbManagerMock.Mock.On("GetLatestGer", ctx, f.cfg.GERFinalityNumberOfBlocks).Return(state.GlobalExitRoot{GlobalExitRoot: tc.ger}, testNow(), nil).Once()
   373  					dbManagerMock.On("BeginStateTransaction", ctx).Return(dbTxMock, nil).Once()
   374  					if tc.openBatchErr == nil {
   375  						dbTxMock.On("Commit", ctx).Return(nil).Once()
   376  					}
   377  				}
   378  				if tc.expectedErr != nil && tc.openBatchErr != nil {
   379  					dbTxMock.On("Rollback", ctx).Return(nil).Once()
   380  				}
   381  			} else {
   382  				dbManagerMock.Mock.On("GetWIPBatch", ctx).Return(tc.expectedBatch, tc.getWIPBatchErr).Once()
   383  			}
   384  
   385  			// act
   386  			err := f.syncWithState(ctx, tc.lastBatchNum)
   387  
   388  			// assert
   389  			if tc.expectedErr != nil {
   390  				assert.Error(t, err)
   391  				assert.EqualError(t, err, tc.expectedErr.Error())
   392  			} else {
   393  				assert.NoError(t, err)
   394  				assert.Equal(t, tc.expectedBatch, f.batch)
   395  			}
   396  			dbManagerMock.AssertExpectations(t)
   397  		})
   398  	}
   399  }
   400  
   401  //func TestFinalizer_processForcedBatches(t *testing.T) {
   402  //	// arrange
   403  //	var err error
   404  //	f = setupFinalizer(false)
   405  //	now = testNow
   406  //	defer func() {
   407  //		now = time.Now
   408  //	}()
   409  //	RawTxsData1 := make([]byte, 0, 2)
   410  //	RawTxsData1 = append(RawTxsData1, []byte("forced tx 1")...)
   411  //	RawTxsData1 = append(RawTxsData1, []byte("forced tx 2")...)
   412  //	RawTxsData2 := make([]byte, 0, 2)
   413  //	RawTxsData2 = append(RawTxsData2, []byte("forced tx 3")...)
   414  //	RawTxsData2 = append(RawTxsData2, []byte("forced tx 4")...)
   415  //	batchNumber := f.batch.batchNumber
   416  //	stateRoot := oldHash
   417  //	forcedBatch1 := state.ForcedBatch{
   418  //		ForcedBatchNumber: 2,
   419  //		GlobalExitRoot:    oldHash,
   420  //		RawTxsData:        RawTxsData1,
   421  //	}
   422  //	forcedBatch2 := state.ForcedBatch{
   423  //		ForcedBatchNumber: 3,
   424  //		GlobalExitRoot:    oldHash,
   425  //		RawTxsData:        RawTxsData2,
   426  //	}
   427  //	testCases := []struct {
   428  //		name                            string
   429  //		forcedBatch                     []state.ForcedBatch
   430  //		getLastTrustedForcedBatchNumErr error
   431  //		expectedErr                     error
   432  //	}{
   433  //		{
   434  //			name:        "Success",
   435  //			forcedBatch: []state.ForcedBatch{forcedBatch1, forcedBatch2},
   436  //		},
   437  //		{
   438  //			name:                            "GetLastTrustedForcedBatchNumber_Error",
   439  //			forcedBatch:                     []state.ForcedBatch{forcedBatch1},
   440  //			getLastTrustedForcedBatchNumErr: testErr,
   441  //			expectedErr:                     fmt.Errorf("failed to get last trusted forced batch number, err: %s", testErr),
   442  //		},
   443  //	}
   444  //
   445  //	for _, tc := range testCases {
   446  //		t.Run(tc.name, func(t *testing.T) {
   447  //			// arrange
   448  //			f.nextForcedBatches = tc.forcedBatch
   449  //			internalBatchNumber := batchNumber
   450  //			dbManagerMock.On("BeginStateTransaction", ctx).Return(dbTxMock, nil).Once()
   451  //			dbManagerMock.On("GetLastTrustedForcedBatchNumber", ctx, dbTxMock).Return(uint64(1), tc.getLastTrustedForcedBatchNumErr).Once()
   452  //
   453  //			for _, forcedBatch := range tc.forcedBatch {
   454  //				internalBatchNumber += 1
   455  //				processRequest := state.ProcessRequest{
   456  //					BatchNumber:    internalBatchNumber,
   457  //					OldStateRoot:   stateRoot,
   458  //					GlobalExitRoot: forcedBatch.GlobalExitRoot,
   459  //					Transactions:   forcedBatch.RawTxsData,
   460  //					Coinbase:       f.sequencerAddress,
   461  //					Timestamp:      now(),
   462  //					Caller:         stateMetrics.SequencerCallerLabel,
   463  //				}
   464  //				dbManagerMock.On("ProcessForcedBatch", forcedBatch.ForcedBatchNumber, processRequest).Return(&state.ProcessBatchResponse{
   465  //					NewStateRoot:   stateRoot,
   466  //					NewBatchNumber: internalBatchNumber,
   467  //				}, nilErr).Once()
   468  //			}
   469  //
   470  //			// act
   471  //			batchNumber, stateRoot, err = f.processForcedBatches(ctx, batchNumber, stateRoot)
   472  //
   473  //			// assert
   474  //			if tc.expectedErr != nil {
   475  //				assert.EqualError(t, err, tc.expectedErr.Error())
   476  //			} else {
   477  //				assert.NoError(t, tc.expectedErr)
   478  //				dbManagerMock.AssertExpectations(t)
   479  //			}
   480  //		})
   481  //	}
   482  //}
   483  
   484  func TestFinalizer_openWIPBatch(t *testing.T) {
   485  	// arrange
   486  	f = setupFinalizer(true)
   487  	now = testNow
   488  	defer func() {
   489  		now = time.Now
   490  	}()
   491  	batchNum := f.batch.batchNumber + 1
   492  	expectedWipBatch := &WipBatch{
   493  		batchNumber:        batchNum,
   494  		coinbase:           f.sequencerAddress,
   495  		initialStateRoot:   oldHash,
   496  		stateRoot:          oldHash,
   497  		timestamp:          now(),
   498  		globalExitRoot:     oldHash,
   499  		remainingResources: getMaxRemainingResources(f.batchConstraints),
   500  	}
   501  	testCases := []struct {
   502  		name         string
   503  		openBatchErr error
   504  		beginTxErr   error
   505  		commitErr    error
   506  		rollbackErr  error
   507  		expectedWip  *WipBatch
   508  		expectedErr  error
   509  	}{
   510  		{
   511  			name:        "Success",
   512  			expectedWip: expectedWipBatch,
   513  		},
   514  		{
   515  			name:        "BeginTransaction Error",
   516  			beginTxErr:  testErr,
   517  			expectedErr: fmt.Errorf("failed to begin state transaction to open batch, err: %w", testErr),
   518  		},
   519  		{
   520  			name:         "OpenBatch Error",
   521  			openBatchErr: testErr,
   522  			expectedErr:  fmt.Errorf("failed to open new batch, err: %w", testErr),
   523  		},
   524  		{
   525  			name:        "Commit Error",
   526  			commitErr:   testErr,
   527  			expectedErr: fmt.Errorf("failed to commit database transaction for opening a batch, err: %w", testErr),
   528  		},
   529  		{
   530  			name:         "Rollback Error",
   531  			openBatchErr: testErr,
   532  			rollbackErr:  testErr,
   533  			expectedErr: fmt.Errorf(
   534  				"failed to rollback dbTx: %s. Rollback err: %w",
   535  				testErr.Error(), openBatchError,
   536  			),
   537  		},
   538  	}
   539  
   540  	for _, tc := range testCases {
   541  		t.Run(tc.name, func(t *testing.T) {
   542  			// arrange
   543  			dbManagerMock.On("BeginStateTransaction", ctx).Return(dbTxMock, tc.beginTxErr).Once()
   544  			if tc.beginTxErr == nil {
   545  				dbManagerMock.On("OpenBatch", ctx, mock.Anything, dbTxMock).Return(tc.openBatchErr).Once()
   546  			}
   547  
   548  			if tc.expectedErr != nil && (tc.rollbackErr != nil || tc.openBatchErr != nil) {
   549  				dbTxMock.On("Rollback", ctx).Return(tc.rollbackErr).Once()
   550  			}
   551  
   552  			if tc.expectedErr == nil || tc.commitErr != nil {
   553  				dbTxMock.On("Commit", ctx).Return(tc.commitErr).Once()
   554  			}
   555  
   556  			// act
   557  			wipBatch, err := f.openWIPBatch(ctx, batchNum, oldHash, oldHash)
   558  
   559  			// assert
   560  			if tc.expectedErr != nil {
   561  				assert.Error(t, err)
   562  				assert.EqualError(t, err, tc.expectedErr.Error())
   563  				assert.Nil(t, wipBatch)
   564  			} else {
   565  				assert.NoError(t, err)
   566  				assert.Equal(t, tc.expectedWip, wipBatch)
   567  			}
   568  			dbManagerMock.AssertExpectations(t)
   569  			dbTxMock.AssertExpectations(t)
   570  		})
   571  	}
   572  }
   573  
   574  // TestFinalizer_closeBatch tests the closeBatch method.
   575  func TestFinalizer_closeBatch(t *testing.T) {
   576  	// arrange
   577  	f = setupFinalizer(true)
   578  	txs := make([]types.Transaction, 0)
   579  	usedResources := getUsedBatchResources(f.batchConstraints, f.batch.remainingResources)
   580  	receipt := ClosingBatchParameters{
   581  		BatchNumber:    f.batch.batchNumber,
   582  		StateRoot:      f.batch.stateRoot,
   583  		LocalExitRoot:  f.processRequest.GlobalExitRoot,
   584  		BatchResources: usedResources,
   585  		Txs:            txs,
   586  	}
   587  	managerErr := fmt.Errorf("some error")
   588  	testCases := []struct {
   589  		name        string
   590  		managerErr  error
   591  		expectedErr error
   592  	}{
   593  		{
   594  			name:        "Success",
   595  			managerErr:  nil,
   596  			expectedErr: nil,
   597  		},
   598  		{
   599  			name:        "Manager Error",
   600  			managerErr:  managerErr,
   601  			expectedErr: fmt.Errorf("failed to get transactions from transactions, err: %w", managerErr),
   602  		},
   603  	}
   604  
   605  	for _, tc := range testCases {
   606  		t.Run(tc.name, func(t *testing.T) {
   607  			// arrange
   608  			dbManagerMock.Mock.On("CloseBatch", ctx, receipt).Return(tc.managerErr).Once()
   609  			dbManagerMock.Mock.On("GetTransactionsByBatchNumber", ctx, receipt.BatchNumber).Return(txs, tc.managerErr).Once()
   610  
   611  			// act
   612  			err := f.closeBatch(ctx)
   613  
   614  			// assert
   615  			if tc.expectedErr != nil {
   616  				assert.Error(t, err)
   617  				assert.EqualError(t, err, tc.expectedErr.Error())
   618  				assert.ErrorIs(t, err, tc.managerErr)
   619  			} else {
   620  				assert.NoError(t, err)
   621  			}
   622  		})
   623  	}
   624  }
   625  
   626  func TestFinalizer_openBatch(t *testing.T) {
   627  	// arrange
   628  	f = setupFinalizer(true)
   629  	now = testNow
   630  	defer func() {
   631  		now = time.Now
   632  	}()
   633  	batchNum := f.batch.batchNumber + 1
   634  	testCases := []struct {
   635  		name        string
   636  		batchNum    uint64
   637  		managerErr  error
   638  		expectedCtx state.ProcessingContext
   639  		expectedErr error
   640  	}{
   641  		{
   642  			name:       "Success",
   643  			batchNum:   batchNum,
   644  			managerErr: nil,
   645  			expectedCtx: state.ProcessingContext{
   646  				BatchNumber:    batchNum,
   647  				Coinbase:       f.sequencerAddress,
   648  				Timestamp:      now(),
   649  				GlobalExitRoot: oldHash,
   650  			},
   651  			expectedErr: nil,
   652  		},
   653  		{
   654  			name:        "Manager Error",
   655  			batchNum:    batchNum,
   656  			managerErr:  testErr,
   657  			expectedCtx: state.ProcessingContext{},
   658  			expectedErr: openBatchError,
   659  		},
   660  	}
   661  
   662  	for _, tc := range testCases {
   663  		t.Run(tc.name, func(t *testing.T) {
   664  			// arrange
   665  			dbManagerMock.Mock.On("OpenBatch", mock.Anything, mock.Anything, mock.Anything).Return(tc.managerErr).Once()
   666  
   667  			// act
   668  			actualCtx, err := f.openBatch(ctx, tc.batchNum, oldHash, nil)
   669  
   670  			// assert
   671  			if tc.expectedErr != nil {
   672  				assert.Error(t, err)
   673  				assert.EqualError(t, err, tc.expectedErr.Error())
   674  				assert.ErrorIs(t, err, tc.managerErr)
   675  				assert.Empty(t, actualCtx)
   676  			} else {
   677  				assert.NoError(t, err)
   678  				assert.Equal(t, tc.expectedCtx, actualCtx)
   679  			}
   680  			dbManagerMock.AssertExpectations(t)
   681  		})
   682  	}
   683  }
   684  
   685  /*
   686  // TestFinalizer_reprocessBatch is a test for reprocessBatch which tests all possible cases of reprocessBatch
   687  func TestFinalizer_reprocessBatch(t *testing.T) {
   688  	// arrange
   689  	now = testNow
   690  	defer func() {
   691  		now = time.Now
   692  	}()
   693  
   694  	f = setupFinalizer(true)
   695  	n := uint(2)
   696  	expectedProcessBatchRequest := state.ProcessRequest{
   697  		BatchNumber:  f.batch.batchNumber,
   698  		OldStateRoot: oldHash,
   699  		Coinbase:     f.sequencerAddress,
   700  		Timestamp:    f.batch.timestamp,
   701  		Caller:       state.DiscardCallerLabel,
   702  	}
   703  	batches := []*state.Batch{
   704  		{
   705  			BatchNumber: f.batch.batchNumber,
   706  			StateRoot:   newHash,
   707  			Timestamp:   testNow(),
   708  		},
   709  		{
   710  			BatchNumber:    f.batch.batchNumber - 1,
   711  			GlobalExitRoot: oldHash,
   712  			StateRoot:      oldHash,
   713  			Timestamp:      testNow(),
   714  		},
   715  	}
   716  
   717  	// TODO: Add missing cases for this test
   718  	testCases := []struct {
   719  		name                       string
   720  		getLastNBatchesErr         error
   721  		processBatchErr            error
   722  		batches                    []*state.Batch
   723  		expectedErr                error
   724  		internalErr                error
   725  		expectedProcessRequest     state.ProcessRequest
   726  		expectedProcessBatchResult *state.ProcessBatchResponse
   727  	}{
   728  		{
   729  			name:                   "Success",
   730  			batches:                batches,
   731  			expectedProcessRequest: expectedProcessBatchRequest,
   732  			expectedProcessBatchResult: &state.ProcessBatchResponse{
   733  				NewStateRoot:     newHash,
   734  				IsBatchProcessed: true,
   735  			},
   736  		},
   737  		{
   738  			name:               "GetLastNBatches Error",
   739  			getLastNBatchesErr: testErr,
   740  			internalErr:        testErr,
   741  			expectedErr:        fmt.Errorf("failed to get old state root, err: failed to get last %d batches, err: %w", n, testErr),
   742  		},
   743  		{
   744  			name:                   "ProcessBatch Error",
   745  			processBatchErr:        testErr,
   746  			internalErr:            testErr,
   747  			expectedErr:            testErr,
   748  			expectedProcessRequest: expectedProcessBatchRequest,
   749  			batches:                batches,
   750  		},
   751  		{
   752  			name:                   "ProcessBatch Result Error",
   753  			processBatchErr:        testErr,
   754  			internalErr:            testErr,
   755  			expectedProcessRequest: expectedProcessBatchRequest,
   756  			expectedErr:            testErr,
   757  			batches:                batches,
   758  			expectedProcessBatchResult: &state.ProcessBatchResponse{
   759  				IsBatchProcessed: false,
   760  				ExecutorError:    testErr2,
   761  			},
   762  		},
   763  	}
   764  
   765  	for _, tc := range testCases {
   766  		t.Run(tc.name, func(t *testing.T) {
   767  			// arrange
   768  			f.processRequest = tc.expectedProcessRequest
   769  			dbManagerMock.On("GetLastNBatches", ctx, n).Return(tc.batches, tc.getLastNBatchesErr).Once()
   770  			if tc.getLastNBatchesErr == nil {
   771  				executorMock.Mock.On("ProcessBatch", ctx, f.processRequest, true).Return(tc.expectedProcessBatchResult, tc.processBatchErr).Once()
   772  				dbManagerMock.On("GetBatchByNumber", ctx, f.batch.batchNumber, nil).Return(tc.batches[0], nil).Once()
   773  			}
   774  
   775  			// act
   776  			err := f.reprocessBatch(ctx, f.batch.batchNumber)
   777  
   778  			// assert
   779  			if tc.expectedErr != nil {
   780  				assert.Error(t, err)
   781  				assert.EqualError(t, err, tc.expectedErr.Error())
   782  				assert.ErrorIs(t, err, tc.internalErr)
   783  			} else {
   784  				assert.NoError(t, err)
   785  			}
   786  		})
   787  	}
   788  }
   789  */
   790  
   791  func TestFinalizer_isDeadlineEncountered(t *testing.T) {
   792  	// arrange
   793  	f = setupFinalizer(true)
   794  	now = testNow
   795  	defer func() {
   796  		now = time.Now
   797  	}()
   798  	testCases := []struct {
   799  		name             string
   800  		nextForcedBatch  int64
   801  		nextGER          int64
   802  		nextDelayedBatch int64
   803  		expected         bool
   804  	}{
   805  		{
   806  			name:             "No deadlines",
   807  			nextForcedBatch:  0,
   808  			nextGER:          0,
   809  			nextDelayedBatch: 0,
   810  			expected:         false,
   811  		},
   812  		{
   813  			name:             "Forced batch deadline",
   814  			nextForcedBatch:  now().Add(time.Second).Unix(),
   815  			nextGER:          0,
   816  			nextDelayedBatch: 0,
   817  			expected:         true,
   818  		},
   819  		{
   820  			name:             "Global Exit Root deadline",
   821  			nextForcedBatch:  0,
   822  			nextGER:          now().Add(time.Second).Unix(),
   823  			nextDelayedBatch: 0,
   824  			expected:         true,
   825  		},
   826  		{
   827  			name:             "Delayed batch deadline",
   828  			nextForcedBatch:  0,
   829  			nextGER:          0,
   830  			nextDelayedBatch: now().Add(time.Second).Unix(),
   831  			expected:         false,
   832  		},
   833  	}
   834  
   835  	for _, tc := range testCases {
   836  		t.Run(tc.name, func(t *testing.T) {
   837  			// arrange
   838  			f.nextForcedBatchDeadline = tc.nextForcedBatch
   839  			f.nextGERDeadline = tc.nextGER
   840  			if tc.expected == true {
   841  				now = func() time.Time {
   842  					return testNow().Add(time.Second * 2)
   843  				}
   844  			}
   845  
   846  			// act
   847  			actual := f.isDeadlineEncountered()
   848  
   849  			// assert
   850  			assert.Equal(t, tc.expected, actual)
   851  		})
   852  	}
   853  }
   854  
   855  func TestFinalizer_checkRemainingResources(t *testing.T) {
   856  	// arrange
   857  	f = setupFinalizer(true)
   858  	ctx := context.Background()
   859  	txResponse := &state.ProcessTransactionResponse{TxHash: oldHash}
   860  	result := &state.ProcessBatchResponse{
   861  		UsedZkCounters: state.ZKCounters{CumulativeGasUsed: 1000},
   862  		Responses:      []*state.ProcessTransactionResponse{txResponse},
   863  	}
   864  	remainingResources := state.BatchResources{
   865  		ZKCounters: state.ZKCounters{CumulativeGasUsed: 9000},
   866  		Bytes:      10000,
   867  	}
   868  	f.batch.remainingResources = remainingResources
   869  	testCases := []struct {
   870  		name                 string
   871  		remaining            state.BatchResources
   872  		expectedErr          error
   873  		expectedWorkerUpdate bool
   874  		expectedTxTracker    *TxTracker
   875  	}{
   876  		{
   877  			name:                 "Success",
   878  			remaining:            remainingResources,
   879  			expectedErr:          nil,
   880  			expectedWorkerUpdate: false,
   881  			expectedTxTracker:    &TxTracker{RawTx: []byte("test")},
   882  		},
   883  		{
   884  			name: "Bytes Resource Exceeded",
   885  			remaining: state.BatchResources{
   886  				Bytes: 0,
   887  			},
   888  			expectedErr:          state.ErrBatchResourceBytesUnderflow,
   889  			expectedWorkerUpdate: true,
   890  			expectedTxTracker:    &TxTracker{RawTx: []byte("test")},
   891  		},
   892  		{
   893  			name: "ZkCounter Resource Exceeded",
   894  			remaining: state.BatchResources{
   895  				ZKCounters: state.ZKCounters{CumulativeGasUsed: 0},
   896  			},
   897  			expectedErr:          state.NewBatchRemainingResourcesUnderflowError(cumulativeGasErr, cumulativeGasErr.Error()),
   898  			expectedWorkerUpdate: true,
   899  			expectedTxTracker:    &TxTracker{RawTx: make([]byte, 0)},
   900  		},
   901  	}
   902  
   903  	for _, tc := range testCases {
   904  		t.Run(tc.name, func(t *testing.T) {
   905  			// arrange
   906  			f.batch.remainingResources = tc.remaining
   907  			dbManagerMock.On("AddEvent", ctx, mock.Anything, nil).Return(nil)
   908  			if tc.expectedWorkerUpdate {
   909  				workerMock.On("UpdateTx", txResponse.TxHash, tc.expectedTxTracker.From, result.UsedZkCounters).Return().Once()
   910  			}
   911  
   912  			// act
   913  			err := f.checkRemainingResources(result, tc.expectedTxTracker)
   914  
   915  			// assert
   916  			if tc.expectedErr != nil {
   917  				assert.Error(t, err)
   918  				assert.EqualError(t, err, tc.expectedErr.Error())
   919  			} else {
   920  				assert.NoError(t, err)
   921  			}
   922  			if tc.expectedWorkerUpdate {
   923  				workerMock.AssertCalled(t, "UpdateTx", txResponse.TxHash, tc.expectedTxTracker.From, result.UsedZkCounters)
   924  			} else {
   925  				workerMock.AssertNotCalled(t, "UpdateTx", mock.Anything, mock.Anything, mock.Anything)
   926  			}
   927  		})
   928  	}
   929  }
   930  
   931  func TestFinalizer_isBatchReadyToClose(t *testing.T) {
   932  	// arrange
   933  	f = setupFinalizer(true)
   934  	maxRemainingResource := getMaxRemainingResources(bc)
   935  	testCases := []struct {
   936  		name              string
   937  		cumulativeGasUsed uint64
   938  		expectedResult    bool
   939  	}{
   940  		{
   941  			name:              "Is ready",
   942  			cumulativeGasUsed: f.getConstraintThresholdUint64(bc.MaxCumulativeGasUsed) - 1,
   943  			expectedResult:    true,
   944  		}, {
   945  			name:              "Is NOT ready",
   946  			cumulativeGasUsed: f.getConstraintThresholdUint64(bc.MaxCumulativeGasUsed) + 1,
   947  			expectedResult:    false,
   948  		},
   949  	}
   950  
   951  	for _, tc := range testCases {
   952  		t.Run(tc.name, func(t *testing.T) {
   953  			maxRemainingResource.ZKCounters.CumulativeGasUsed = tc.cumulativeGasUsed
   954  			f.batch.remainingResources = maxRemainingResource
   955  			// act
   956  			result := f.isBatchAlmostFull()
   957  
   958  			// assert
   959  			assert.Equal(t, tc.expectedResult, result)
   960  		})
   961  	}
   962  }
   963  
   964  func TestFinalizer_setNextForcedBatchDeadline(t *testing.T) {
   965  	// arrange
   966  	f = setupFinalizer(false)
   967  	now = testNow
   968  	defer func() {
   969  		now = time.Now
   970  	}()
   971  	expected := now().Unix() + int64(f.cfg.ForcedBatchDeadlineTimeout.Duration.Seconds())
   972  
   973  	// act
   974  	f.setNextForcedBatchDeadline()
   975  
   976  	// assert
   977  	assert.Equal(t, expected, f.nextForcedBatchDeadline)
   978  }
   979  
   980  func TestFinalizer_setNextGERDeadline(t *testing.T) {
   981  	// arrange
   982  	f = setupFinalizer(false)
   983  	now = testNow
   984  	defer func() {
   985  		now = time.Now
   986  	}()
   987  	expected := now().Unix() + int64(f.cfg.GERDeadlineTimeout.Duration.Seconds())
   988  
   989  	// act
   990  	f.setNextGERDeadline()
   991  
   992  	// assert
   993  	assert.Equal(t, expected, f.nextGERDeadline)
   994  }
   995  
   996  func TestFinalizer_getConstraintThresholdUint64(t *testing.T) {
   997  	// arrange
   998  	f = setupFinalizer(false)
   999  	input := uint64(100)
  1000  	expect := input * uint64(f.cfg.ResourcePercentageToCloseBatch) / 100
  1001  
  1002  	// act
  1003  	result := f.getConstraintThresholdUint64(input)
  1004  
  1005  	// assert
  1006  	assert.Equal(t, result, expect)
  1007  }
  1008  
  1009  func TestFinalizer_getConstraintThresholdUint32(t *testing.T) {
  1010  	// arrange
  1011  	f = setupFinalizer(false)
  1012  	input := uint32(100)
  1013  	expect := uint32(input * f.cfg.ResourcePercentageToCloseBatch / 100)
  1014  
  1015  	// act
  1016  	result := f.getConstraintThresholdUint32(input)
  1017  
  1018  	// assert
  1019  	assert.Equal(t, result, expect)
  1020  }
  1021  
  1022  func TestFinalizer_getRemainingResources(t *testing.T) {
  1023  	// act
  1024  	remainingResources := getMaxRemainingResources(bc)
  1025  
  1026  	// assert
  1027  	assert.Equal(t, remainingResources.ZKCounters.CumulativeGasUsed, bc.MaxCumulativeGasUsed)
  1028  	assert.Equal(t, remainingResources.ZKCounters.UsedKeccakHashes, bc.MaxKeccakHashes)
  1029  	assert.Equal(t, remainingResources.ZKCounters.UsedPoseidonHashes, bc.MaxPoseidonHashes)
  1030  	assert.Equal(t, remainingResources.ZKCounters.UsedPoseidonPaddings, bc.MaxPoseidonPaddings)
  1031  	assert.Equal(t, remainingResources.ZKCounters.UsedMemAligns, bc.MaxMemAligns)
  1032  	assert.Equal(t, remainingResources.ZKCounters.UsedArithmetics, bc.MaxArithmetics)
  1033  	assert.Equal(t, remainingResources.ZKCounters.UsedBinaries, bc.MaxBinaries)
  1034  	assert.Equal(t, remainingResources.ZKCounters.UsedSteps, bc.MaxSteps)
  1035  	assert.Equal(t, remainingResources.Bytes, bc.MaxBatchBytesSize)
  1036  }
  1037  
  1038  func setupFinalizer(withWipBatch bool) *finalizer {
  1039  	wipBatch := new(WipBatch)
  1040  	dbManagerMock = new(DbManagerMock)
  1041  	executorMock = new(StateMock)
  1042  	workerMock = new(WorkerMock)
  1043  	dbTxMock = new(DbTxMock)
  1044  	if withWipBatch {
  1045  		wipBatch = &WipBatch{
  1046  			batchNumber:        1,
  1047  			coinbase:           seqAddr,
  1048  			initialStateRoot:   oldHash,
  1049  			stateRoot:          newHash,
  1050  			timestamp:          now(),
  1051  			globalExitRoot:     oldHash,
  1052  			remainingResources: getMaxRemainingResources(bc),
  1053  		}
  1054  	}
  1055  	return &finalizer{
  1056  		cfg:                cfg,
  1057  		txsStore:           txsStore,
  1058  		closingSignalCh:    closingSignalCh,
  1059  		isSynced:           isSynced,
  1060  		sequencerAddress:   seqAddr,
  1061  		worker:             workerMock,
  1062  		dbManager:          dbManagerMock,
  1063  		executor:           executorMock,
  1064  		sharedResourcesMux: new(sync.RWMutex),
  1065  		batch:              wipBatch,
  1066  		batchConstraints:   bc,
  1067  		processRequest:     state.ProcessRequest{},
  1068  		// closing signals
  1069  		nextGER:                 common.Hash{},
  1070  		nextGERDeadline:         0,
  1071  		nextGERMux:              new(sync.RWMutex),
  1072  		nextForcedBatches:       make([]state.ForcedBatch, 0),
  1073  		nextForcedBatchDeadline: 0,
  1074  		nextForcedBatchesMux:    new(sync.RWMutex),
  1075  	}
  1076  }
  1077  
  1078  func TestFinalizer_handleTransactionError(t *testing.T) {
  1079  	// arrange
  1080  	f = setupFinalizer(true)
  1081  	nonce := uint64(0)
  1082  	tx := &TxTracker{Hash: oldHash, From: sender, Cost: big.NewInt(0)}
  1083  	testCases := []struct {
  1084  		name               string
  1085  		error              pb.RomError
  1086  		expectedDeleteCall bool
  1087  		updateTxStatus     pool.TxStatus
  1088  		expectedMoveCall   bool
  1089  	}{
  1090  		{
  1091  			name:               "OutOfCountersError",
  1092  			error:              pb.RomError(executor.ROM_ERROR_OUT_OF_COUNTERS_STEP),
  1093  			updateTxStatus:     pool.TxStatusInvalid,
  1094  			expectedDeleteCall: true,
  1095  		},
  1096  		{
  1097  			name:             "IntrinsicError",
  1098  			error:            pb.RomError(executor.ROM_ERROR_INTRINSIC_INVALID_NONCE),
  1099  			updateTxStatus:   pool.TxStatusFailed,
  1100  			expectedMoveCall: true,
  1101  		},
  1102  	}
  1103  	for _, tc := range testCases {
  1104  		t.Run(tc.name, func(t *testing.T) {
  1105  			// arrange
  1106  			if tc.expectedDeleteCall {
  1107  				workerMock.On("DeleteTx", oldHash, sender).Return()
  1108  				dbManagerMock.On("UpdateTxStatus", ctx, oldHash, tc.updateTxStatus, false, mock.Anything).Return(nil).Once()
  1109  				dbManagerMock.On("DeleteTransactionFromPool", ctx, tx.Hash).Return(nil).Once()
  1110  			}
  1111  			if tc.expectedMoveCall {
  1112  				workerMock.On("MoveTxToNotReady", oldHash, sender, &nonce, big.NewInt(0)).Return([]*TxTracker{}).Once()
  1113  			}
  1114  
  1115  			result := &state.ProcessBatchResponse{
  1116  				ReadWriteAddresses: map[common.Address]*state.InfoReadWrite{
  1117  					sender: {Nonce: &nonce, Balance: big.NewInt(0)},
  1118  				},
  1119  				Responses: []*state.ProcessTransactionResponse{{
  1120  					RomError: executor.RomErr(tc.error),
  1121  				},
  1122  				},
  1123  			}
  1124  
  1125  			// act
  1126  			wg := f.handleProcessTransactionError(ctx, result, tx)
  1127  			if wg != nil {
  1128  				wg.Wait()
  1129  			}
  1130  
  1131  			// assert
  1132  			workerMock.AssertExpectations(t)
  1133  		})
  1134  	}
  1135  }