github.com/ethereum-optimism/optimism@v1.7.2/op-node/rollup/derive/batches_test.go (about)

     1  package derive
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"math/big"
     7  	"math/rand"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"github.com/ethereum-optimism/optimism/op-node/rollup"
    13  	"github.com/ethereum-optimism/optimism/op-service/eth"
    14  	"github.com/ethereum-optimism/optimism/op-service/testlog"
    15  	"github.com/ethereum-optimism/optimism/op-service/testutils"
    16  	"github.com/ethereum/go-ethereum/common/hexutil"
    17  	"github.com/ethereum/go-ethereum/core/types"
    18  	"github.com/ethereum/go-ethereum/log"
    19  )
    20  
    21  type ValidBatchTestCase struct {
    22  	Name           string
    23  	L1Blocks       []eth.L1BlockRef
    24  	L2SafeHead     eth.L2BlockRef
    25  	Batch          BatchWithL1InclusionBlock
    26  	Expected       BatchValidity
    27  	ExpectedLog    string // log message that must be included
    28  	NotExpectedLog string // log message that must not be included
    29  	DeltaTime      *uint64
    30  }
    31  
    32  func TestValidBatch(t *testing.T) {
    33  	defaultConf := rollup.Config{
    34  		Genesis: rollup.Genesis{
    35  			L2Time: 31, // a genesis time that itself does not align to make it more interesting
    36  		},
    37  		BlockTime:         2,
    38  		SeqWindowSize:     4,
    39  		MaxSequencerDrift: 6,
    40  		// other config fields are ignored and can be left empty.
    41  		DeltaTime: nil,
    42  	}
    43  
    44  	rng := rand.New(rand.NewSource(1234))
    45  
    46  	minTs := uint64(0)
    47  	chainId := new(big.Int).SetUint64(rng.Uint64())
    48  	signer := types.NewLondonSigner(chainId)
    49  	randTx := testutils.RandomTx(rng, new(big.Int).SetUint64(rng.Uint64()), signer)
    50  	randTxData, _ := randTx.MarshalBinary()
    51  
    52  	l1A := testutils.RandomBlockRef(rng)
    53  	l1B := eth.L1BlockRef{
    54  		Hash:       testutils.RandomHash(rng),
    55  		Number:     l1A.Number + 1,
    56  		ParentHash: l1A.Hash,
    57  		Time:       l1A.Time + 7,
    58  	}
    59  	l1C := eth.L1BlockRef{
    60  		Hash:       testutils.RandomHash(rng),
    61  		Number:     l1B.Number + 1,
    62  		ParentHash: l1B.Hash,
    63  		Time:       l1B.Time + 7,
    64  	}
    65  	l1D := eth.L1BlockRef{
    66  		Hash:       testutils.RandomHash(rng),
    67  		Number:     l1C.Number + 1,
    68  		ParentHash: l1C.Hash,
    69  		Time:       l1C.Time + 7,
    70  	}
    71  	l1E := eth.L1BlockRef{
    72  		Hash:       testutils.RandomHash(rng),
    73  		Number:     l1D.Number + 1,
    74  		ParentHash: l1D.Hash,
    75  		Time:       l1D.Time + 7,
    76  	}
    77  	l1F := eth.L1BlockRef{
    78  		Hash:       testutils.RandomHash(rng),
    79  		Number:     l1E.Number + 1,
    80  		ParentHash: l1E.Hash,
    81  		Time:       l1E.Time + 7,
    82  	}
    83  
    84  	l2A0 := eth.L2BlockRef{
    85  		Hash:           testutils.RandomHash(rng),
    86  		Number:         100,
    87  		ParentHash:     testutils.RandomHash(rng),
    88  		Time:           l1A.Time,
    89  		L1Origin:       l1A.ID(),
    90  		SequenceNumber: 0,
    91  	}
    92  
    93  	l2A1 := eth.L2BlockRef{
    94  		Hash:           testutils.RandomHash(rng),
    95  		Number:         l2A0.Number + 1,
    96  		ParentHash:     l2A0.Hash,
    97  		Time:           l2A0.Time + defaultConf.BlockTime,
    98  		L1Origin:       l1A.ID(),
    99  		SequenceNumber: 1,
   100  	}
   101  
   102  	l2A2 := eth.L2BlockRef{
   103  		Hash:           testutils.RandomHash(rng),
   104  		Number:         l2A1.Number + 1,
   105  		ParentHash:     l2A1.Hash,
   106  		Time:           l2A1.Time + defaultConf.BlockTime,
   107  		L1Origin:       l1A.ID(),
   108  		SequenceNumber: 2,
   109  	}
   110  
   111  	l2A3 := eth.L2BlockRef{
   112  		Hash:           testutils.RandomHash(rng),
   113  		Number:         l2A2.Number + 1,
   114  		ParentHash:     l2A2.Hash,
   115  		Time:           l2A2.Time + defaultConf.BlockTime,
   116  		L1Origin:       l1A.ID(),
   117  		SequenceNumber: 3,
   118  	}
   119  
   120  	l2B0 := eth.L2BlockRef{
   121  		Hash:           testutils.RandomHash(rng),
   122  		Number:         l2A3.Number + 1,
   123  		ParentHash:     l2A3.Hash,
   124  		Time:           l2A3.Time + defaultConf.BlockTime, // 8 seconds larger than l1A0, 1 larger than origin
   125  		L1Origin:       l1B.ID(),
   126  		SequenceNumber: 0,
   127  	}
   128  
   129  	l2B1 := eth.L2BlockRef{
   130  		Hash:           testutils.RandomHash(rng),
   131  		Number:         l2B0.Number + 1,
   132  		ParentHash:     l2B0.Hash,
   133  		Time:           l2B0.Time + defaultConf.BlockTime,
   134  		L1Origin:       l1B.ID(),
   135  		SequenceNumber: 1,
   136  	}
   137  
   138  	l2B2 := eth.L2BlockRef{
   139  		Hash:           testutils.RandomHash(rng),
   140  		Number:         l2B1.Number + 1,
   141  		ParentHash:     l2B1.Hash,
   142  		Time:           l2B1.Time + defaultConf.BlockTime,
   143  		L1Origin:       l1B.ID(),
   144  		SequenceNumber: 2,
   145  	}
   146  
   147  	l1X := eth.L1BlockRef{
   148  		Hash:       testutils.RandomHash(rng),
   149  		Number:     42,
   150  		ParentHash: testutils.RandomHash(rng),
   151  		Time:       10_000,
   152  	}
   153  	l1Y := eth.L1BlockRef{
   154  		Hash:       testutils.RandomHash(rng),
   155  		Number:     l1X.Number + 1,
   156  		ParentHash: l1X.Hash,
   157  		Time:       l1X.Time + 12,
   158  	}
   159  	l1Z := eth.L1BlockRef{
   160  		Hash:       testutils.RandomHash(rng),
   161  		Number:     l1Y.Number + 1,
   162  		ParentHash: l1Y.Hash,
   163  		Time:       l1Y.Time + 12,
   164  	}
   165  	l2X0 := eth.L2BlockRef{
   166  		Hash:           testutils.RandomHash(rng),
   167  		Number:         1000,
   168  		ParentHash:     testutils.RandomHash(rng),
   169  		Time:           10_000 + 24 + 6 - 1, // add one block, and you get ahead of next l1 block by more than the drift
   170  		L1Origin:       l1X.ID(),
   171  		SequenceNumber: 0,
   172  	}
   173  	l2Y0 := eth.L2BlockRef{
   174  		Hash:           testutils.RandomHash(rng),
   175  		Number:         l2X0.Number + 1,
   176  		ParentHash:     l2X0.Hash,
   177  		Time:           l2X0.Time + defaultConf.BlockTime, // exceeds sequencer time drift, forced to be empty block
   178  		L1Origin:       l1Y.ID(),
   179  		SequenceNumber: 0,
   180  	}
   181  	l2Z0 := eth.L2BlockRef{
   182  		Hash:           testutils.RandomHash(rng),
   183  		Number:         l2Y0.Number + 1,
   184  		ParentHash:     l2Y0.Hash,
   185  		Time:           l2Y0.Time + defaultConf.BlockTime, // exceeds sequencer time drift, forced to be empty block
   186  		L1Origin:       l1Z.ID(),
   187  		SequenceNumber: 0,
   188  	}
   189  
   190  	l2A4 := eth.L2BlockRef{
   191  		Hash:           testutils.RandomHash(rng),
   192  		Number:         l2A3.Number + 1,
   193  		ParentHash:     l2A3.Hash,
   194  		Time:           l2A3.Time + defaultConf.BlockTime, // 4*2 = 8, higher than seq time drift
   195  		L1Origin:       l1A.ID(),
   196  		SequenceNumber: 4,
   197  	}
   198  
   199  	l1BLate := eth.L1BlockRef{
   200  		Hash:       testutils.RandomHash(rng),
   201  		Number:     l1A.Number + 1,
   202  		ParentHash: l1A.Hash,
   203  		Time:       l2A4.Time + 1, // too late for l2A4 to adopt yet
   204  	}
   205  
   206  	singularBatchTestCases := []ValidBatchTestCase{
   207  		{
   208  			Name:       "missing L1 info",
   209  			L1Blocks:   []eth.L1BlockRef{},
   210  			L2SafeHead: l2A0,
   211  			Batch: BatchWithL1InclusionBlock{
   212  				L1InclusionBlock: l1B,
   213  				Batch: &SingularBatch{
   214  					ParentHash:   l2A1.ParentHash,
   215  					EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
   216  					EpochHash:    l2A1.L1Origin.Hash,
   217  					Timestamp:    l2A1.Time,
   218  					Transactions: nil,
   219  				},
   220  			},
   221  			Expected: BatchUndecided,
   222  		},
   223  		{
   224  			Name:       "future timestamp",
   225  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C},
   226  			L2SafeHead: l2A0,
   227  			Batch: BatchWithL1InclusionBlock{
   228  				L1InclusionBlock: l1B,
   229  				Batch: &SingularBatch{
   230  					ParentHash:   l2A1.ParentHash,
   231  					EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
   232  					EpochHash:    l2A1.L1Origin.Hash,
   233  					Timestamp:    l2A1.Time + 1, // 1 too high
   234  					Transactions: nil,
   235  				},
   236  			},
   237  			Expected: BatchFuture,
   238  		},
   239  		{
   240  			Name:       "old timestamp",
   241  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C},
   242  			L2SafeHead: l2A0,
   243  			Batch: BatchWithL1InclusionBlock{
   244  				L1InclusionBlock: l1B,
   245  				Batch: &SingularBatch{
   246  					ParentHash:   l2A1.ParentHash,
   247  					EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
   248  					EpochHash:    l2A1.L1Origin.Hash,
   249  					Timestamp:    l2A0.Time, // repeating the same time
   250  					Transactions: nil,
   251  				},
   252  			},
   253  			Expected: BatchDrop,
   254  		},
   255  		{
   256  			Name:       "misaligned timestamp",
   257  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C},
   258  			L2SafeHead: l2A0,
   259  			Batch: BatchWithL1InclusionBlock{
   260  				L1InclusionBlock: l1B,
   261  				Batch: &SingularBatch{
   262  					ParentHash:   l2A1.ParentHash,
   263  					EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
   264  					EpochHash:    l2A1.L1Origin.Hash,
   265  					Timestamp:    l2A1.Time - 1, // block time is 2, so this is 1 too low
   266  					Transactions: nil,
   267  				},
   268  			},
   269  			Expected: BatchDrop,
   270  		},
   271  		{
   272  			Name:       "invalid parent block hash",
   273  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C},
   274  			L2SafeHead: l2A0,
   275  			Batch: BatchWithL1InclusionBlock{
   276  				L1InclusionBlock: l1B,
   277  				Batch: &SingularBatch{
   278  					ParentHash:   testutils.RandomHash(rng),
   279  					EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
   280  					EpochHash:    l2A1.L1Origin.Hash,
   281  					Timestamp:    l2A1.Time,
   282  					Transactions: nil,
   283  				},
   284  			},
   285  			Expected: BatchDrop,
   286  		},
   287  		{
   288  			Name:       "sequence window expired",
   289  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C, l1D, l1E, l1F},
   290  			L2SafeHead: l2A0,
   291  			Batch: BatchWithL1InclusionBlock{
   292  				L1InclusionBlock: l1F, // included in 5th block after epoch of batch, while seq window is 4
   293  				Batch: &SingularBatch{
   294  					ParentHash:   l2A1.ParentHash,
   295  					EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
   296  					EpochHash:    l2A1.L1Origin.Hash,
   297  					Timestamp:    l2A1.Time,
   298  					Transactions: nil,
   299  				},
   300  			},
   301  			Expected: BatchDrop,
   302  		},
   303  		{
   304  			Name:       "epoch too old, but good parent hash and timestamp", // repeat of now outdated l2A3 data
   305  			L1Blocks:   []eth.L1BlockRef{l1B, l1C, l1D},
   306  			L2SafeHead: l2B0, // we already moved on to B
   307  			Batch: BatchWithL1InclusionBlock{
   308  				L1InclusionBlock: l1C,
   309  				Batch: &SingularBatch{
   310  					ParentHash:   l2B0.Hash,                          // build on top of safe head to continue
   311  					EpochNum:     rollup.Epoch(l2A3.L1Origin.Number), // epoch A is no longer valid
   312  					EpochHash:    l2A3.L1Origin.Hash,
   313  					Timestamp:    l2B0.Time + defaultConf.BlockTime, // pass the timestamp check to get too epoch check
   314  					Transactions: nil,
   315  				},
   316  			},
   317  			Expected: BatchDrop,
   318  		},
   319  		{
   320  			Name:       "insufficient L1 info for eager derivation",
   321  			L1Blocks:   []eth.L1BlockRef{l1A}, // don't know about l1B yet
   322  			L2SafeHead: l2A3,
   323  			Batch: BatchWithL1InclusionBlock{
   324  				L1InclusionBlock: l1C,
   325  				Batch: &SingularBatch{
   326  					ParentHash:   l2B0.ParentHash,
   327  					EpochNum:     rollup.Epoch(l2B0.L1Origin.Number),
   328  					EpochHash:    l2B0.L1Origin.Hash,
   329  					Timestamp:    l2B0.Time,
   330  					Transactions: nil,
   331  				},
   332  			},
   333  			Expected: BatchUndecided,
   334  		},
   335  		{
   336  			Name:       "epoch too new",
   337  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C, l1D},
   338  			L2SafeHead: l2A3,
   339  			Batch: BatchWithL1InclusionBlock{
   340  				L1InclusionBlock: l1D,
   341  				Batch: &SingularBatch{
   342  					ParentHash:   l2B0.ParentHash,
   343  					EpochNum:     rollup.Epoch(l1C.Number), // invalid, we need to adopt epoch B before C
   344  					EpochHash:    l1C.Hash,
   345  					Timestamp:    l2B0.Time,
   346  					Transactions: nil,
   347  				},
   348  			},
   349  			Expected: BatchDrop,
   350  		},
   351  		{
   352  			Name:       "epoch hash wrong",
   353  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
   354  			L2SafeHead: l2A3,
   355  			Batch: BatchWithL1InclusionBlock{
   356  				L1InclusionBlock: l1C,
   357  				Batch: &SingularBatch{
   358  					ParentHash:   l2B0.ParentHash,
   359  					EpochNum:     rollup.Epoch(l2B0.L1Origin.Number),
   360  					EpochHash:    l1A.Hash, // invalid, epoch hash should be l1B
   361  					Timestamp:    l2B0.Time,
   362  					Transactions: nil,
   363  				},
   364  			},
   365  			Expected: BatchDrop,
   366  		},
   367  		{
   368  			Name:       "sequencer time drift on same epoch with non-empty txs",
   369  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
   370  			L2SafeHead: l2A3,
   371  			Batch: BatchWithL1InclusionBlock{
   372  				L1InclusionBlock: l1B,
   373  				Batch: &SingularBatch{ // we build l2A4, which has a timestamp of 2*4 = 8 higher than l2A0
   374  					ParentHash:   l2A4.ParentHash,
   375  					EpochNum:     rollup.Epoch(l2A4.L1Origin.Number),
   376  					EpochHash:    l2A4.L1Origin.Hash,
   377  					Timestamp:    l2A4.Time,
   378  					Transactions: []hexutil.Bytes{[]byte("sequencer should not include this tx")},
   379  				},
   380  			},
   381  			Expected: BatchDrop,
   382  		},
   383  		{
   384  			Name:       "sequencer time drift on changing epoch with non-empty txs",
   385  			L1Blocks:   []eth.L1BlockRef{l1X, l1Y, l1Z},
   386  			L2SafeHead: l2X0,
   387  			Batch: BatchWithL1InclusionBlock{
   388  				L1InclusionBlock: l1Z,
   389  				Batch: &SingularBatch{
   390  					ParentHash:   l2Y0.ParentHash,
   391  					EpochNum:     rollup.Epoch(l2Y0.L1Origin.Number),
   392  					EpochHash:    l2Y0.L1Origin.Hash,
   393  					Timestamp:    l2Y0.Time, // valid, but more than 6 ahead of l1Y.Time
   394  					Transactions: []hexutil.Bytes{[]byte("sequencer should not include this tx")},
   395  				},
   396  			},
   397  			Expected: BatchDrop,
   398  		},
   399  		{
   400  			Name:       "sequencer time drift on same epoch with empty txs and late next epoch",
   401  			L1Blocks:   []eth.L1BlockRef{l1A, l1BLate},
   402  			L2SafeHead: l2A3,
   403  			Batch: BatchWithL1InclusionBlock{
   404  				L1InclusionBlock: l1BLate,
   405  				Batch: &SingularBatch{ // l2A4 time < l1BLate time, so we cannot adopt origin B yet
   406  					ParentHash:   l2A4.ParentHash,
   407  					EpochNum:     rollup.Epoch(l2A4.L1Origin.Number),
   408  					EpochHash:    l2A4.L1Origin.Hash,
   409  					Timestamp:    l2A4.Time,
   410  					Transactions: nil,
   411  				},
   412  			},
   413  			Expected: BatchAccept, // accepted because empty & preserving L2 time invariant
   414  		},
   415  		{
   416  			Name:       "sequencer time drift on changing epoch with empty txs",
   417  			L1Blocks:   []eth.L1BlockRef{l1X, l1Y, l1Z},
   418  			L2SafeHead: l2X0,
   419  			Batch: BatchWithL1InclusionBlock{
   420  				L1InclusionBlock: l1Z,
   421  				Batch: &SingularBatch{
   422  					ParentHash:   l2Y0.ParentHash,
   423  					EpochNum:     rollup.Epoch(l2Y0.L1Origin.Number),
   424  					EpochHash:    l2Y0.L1Origin.Hash,
   425  					Timestamp:    l2Y0.Time, // valid, but more than 6 ahead of l1Y.Time
   426  					Transactions: nil,
   427  				},
   428  			},
   429  			Expected: BatchAccept, // accepted because empty & still advancing epoch
   430  		},
   431  		{
   432  			Name:       "sequencer time drift on same epoch with empty txs and no next epoch in sight yet",
   433  			L1Blocks:   []eth.L1BlockRef{l1A},
   434  			L2SafeHead: l2A3,
   435  			Batch: BatchWithL1InclusionBlock{
   436  				L1InclusionBlock: l1B,
   437  				Batch: &SingularBatch{ // we build l2A4, which has a timestamp of 2*4 = 8 higher than l2A0
   438  					ParentHash:   l2A4.ParentHash,
   439  					EpochNum:     rollup.Epoch(l2A4.L1Origin.Number),
   440  					EpochHash:    l2A4.L1Origin.Hash,
   441  					Timestamp:    l2A4.Time,
   442  					Transactions: nil,
   443  				},
   444  			},
   445  			Expected: BatchUndecided, // we have to wait till the next epoch is in sight to check the time
   446  		},
   447  		{
   448  			Name:       "sequencer time drift on same epoch with empty txs and but in-sight epoch that invalidates it",
   449  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C},
   450  			L2SafeHead: l2A3,
   451  			Batch: BatchWithL1InclusionBlock{
   452  				L1InclusionBlock: l1C,
   453  				Batch: &SingularBatch{ // we build l2A4, which has a timestamp of 2*4 = 8 higher than l2A0
   454  					ParentHash:   l2A4.ParentHash,
   455  					EpochNum:     rollup.Epoch(l2A4.L1Origin.Number),
   456  					EpochHash:    l2A4.L1Origin.Hash,
   457  					Timestamp:    l2A4.Time,
   458  					Transactions: nil,
   459  				},
   460  			},
   461  			Expected: BatchDrop, // dropped because it could have advanced the epoch to B
   462  		},
   463  		{
   464  			Name:       "empty tx included",
   465  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
   466  			L2SafeHead: l2A0,
   467  			Batch: BatchWithL1InclusionBlock{
   468  				L1InclusionBlock: l1B,
   469  				Batch: &SingularBatch{
   470  					ParentHash: l2A1.ParentHash,
   471  					EpochNum:   rollup.Epoch(l2A1.L1Origin.Number),
   472  					EpochHash:  l2A1.L1Origin.Hash,
   473  					Timestamp:  l2A1.Time,
   474  					Transactions: []hexutil.Bytes{
   475  						[]byte{}, // empty tx data
   476  					},
   477  				},
   478  			},
   479  			Expected: BatchDrop,
   480  		},
   481  		{
   482  			Name:       "deposit tx included",
   483  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
   484  			L2SafeHead: l2A0,
   485  			Batch: BatchWithL1InclusionBlock{
   486  				L1InclusionBlock: l1B,
   487  				Batch: &SingularBatch{
   488  					ParentHash: l2A1.ParentHash,
   489  					EpochNum:   rollup.Epoch(l2A1.L1Origin.Number),
   490  					EpochHash:  l2A1.L1Origin.Hash,
   491  					Timestamp:  l2A1.Time,
   492  					Transactions: []hexutil.Bytes{
   493  						[]byte{types.DepositTxType, 0}, // piece of data alike to a deposit
   494  					},
   495  				},
   496  			},
   497  			Expected: BatchDrop,
   498  		},
   499  		{
   500  			Name:       "valid batch same epoch",
   501  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
   502  			L2SafeHead: l2A0,
   503  			Batch: BatchWithL1InclusionBlock{
   504  				L1InclusionBlock: l1B,
   505  				Batch: &SingularBatch{
   506  					ParentHash: l2A1.ParentHash,
   507  					EpochNum:   rollup.Epoch(l2A1.L1Origin.Number),
   508  					EpochHash:  l2A1.L1Origin.Hash,
   509  					Timestamp:  l2A1.Time,
   510  					Transactions: []hexutil.Bytes{
   511  						[]byte{0x02, 0x42, 0x13, 0x37},
   512  						[]byte{0x02, 0xde, 0xad, 0xbe, 0xef},
   513  					},
   514  				},
   515  			},
   516  			Expected: BatchAccept,
   517  		},
   518  		{
   519  			Name:       "valid batch changing epoch",
   520  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C},
   521  			L2SafeHead: l2A3,
   522  			Batch: BatchWithL1InclusionBlock{
   523  				L1InclusionBlock: l1C,
   524  				Batch: &SingularBatch{
   525  					ParentHash: l2B0.ParentHash,
   526  					EpochNum:   rollup.Epoch(l2B0.L1Origin.Number),
   527  					EpochHash:  l2B0.L1Origin.Hash,
   528  					Timestamp:  l2B0.Time,
   529  					Transactions: []hexutil.Bytes{
   530  						[]byte{0x02, 0x42, 0x13, 0x37},
   531  						[]byte{0x02, 0xde, 0xad, 0xbe, 0xef},
   532  					},
   533  				},
   534  			},
   535  			Expected: BatchAccept,
   536  		},
   537  		{
   538  			Name:       "batch with L2 time before L1 time",
   539  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C},
   540  			L2SafeHead: l2A2,
   541  			Batch: BatchWithL1InclusionBlock{
   542  				L1InclusionBlock: l1B,
   543  				Batch: &SingularBatch{ // we build l2B0', which starts a new epoch too early
   544  					ParentHash:   l2A2.Hash,
   545  					EpochNum:     rollup.Epoch(l2B0.L1Origin.Number),
   546  					EpochHash:    l2B0.L1Origin.Hash,
   547  					Timestamp:    l2A2.Time + defaultConf.BlockTime,
   548  					Transactions: nil,
   549  				},
   550  			},
   551  			Expected: BatchDrop,
   552  		},
   553  	}
   554  	spanBatchTestCases := []ValidBatchTestCase{
   555  		{
   556  			Name:       "missing L1 info",
   557  			L1Blocks:   []eth.L1BlockRef{},
   558  			L2SafeHead: l2A0,
   559  			Batch: BatchWithL1InclusionBlock{
   560  				L1InclusionBlock: l1B,
   561  				Batch: NewSpanBatch([]*SingularBatch{
   562  					{
   563  						ParentHash:   l2A1.ParentHash,
   564  						EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
   565  						EpochHash:    l2A1.L1Origin.Hash,
   566  						Timestamp:    l2A1.Time,
   567  						Transactions: nil,
   568  					},
   569  				}),
   570  			},
   571  			Expected:    BatchUndecided,
   572  			ExpectedLog: "missing L1 block input, cannot proceed with batch checking",
   573  			DeltaTime:   &minTs,
   574  		},
   575  		{
   576  			Name:       "future timestamp",
   577  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C},
   578  			L2SafeHead: l2A0,
   579  			Batch: BatchWithL1InclusionBlock{
   580  				L1InclusionBlock: l1B,
   581  				Batch: NewSpanBatch([]*SingularBatch{
   582  					{
   583  						ParentHash:   l2A1.ParentHash,
   584  						EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
   585  						EpochHash:    l2A1.L1Origin.Hash,
   586  						Timestamp:    l2A1.Time + 1, // 1 too high
   587  						Transactions: nil,
   588  					},
   589  				}),
   590  			},
   591  			Expected:    BatchFuture,
   592  			ExpectedLog: "received out-of-order batch for future processing after next batch",
   593  			DeltaTime:   &minTs,
   594  		},
   595  		{
   596  			Name:       "misaligned timestamp",
   597  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C},
   598  			L2SafeHead: l2A0,
   599  			Batch: BatchWithL1InclusionBlock{
   600  				L1InclusionBlock: l1B,
   601  				Batch: NewSpanBatch([]*SingularBatch{
   602  					{
   603  						ParentHash:   l2A1.ParentHash,
   604  						EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
   605  						EpochHash:    l2A1.L1Origin.Hash,
   606  						Timestamp:    l2A1.Time - 1, // block time is 2, so this is 1 too low
   607  						Transactions: nil,
   608  					},
   609  				}),
   610  			},
   611  			Expected:    BatchDrop,
   612  			ExpectedLog: "span batch has no new blocks after safe head",
   613  			DeltaTime:   &minTs,
   614  		},
   615  		{
   616  			Name:       "invalid parent block hash",
   617  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C},
   618  			L2SafeHead: l2A0,
   619  			Batch: BatchWithL1InclusionBlock{
   620  				L1InclusionBlock: l1B,
   621  				Batch: NewSpanBatch([]*SingularBatch{
   622  					{
   623  						ParentHash:   testutils.RandomHash(rng),
   624  						EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
   625  						EpochHash:    l2A1.L1Origin.Hash,
   626  						Timestamp:    l2A1.Time,
   627  						Transactions: nil,
   628  					},
   629  				}),
   630  			},
   631  			Expected:    BatchDrop,
   632  			ExpectedLog: "ignoring batch with mismatching parent hash",
   633  			DeltaTime:   &minTs,
   634  		},
   635  		{
   636  			Name:       "sequence window expired",
   637  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C, l1D, l1E, l1F},
   638  			L2SafeHead: l2A0,
   639  			Batch: BatchWithL1InclusionBlock{
   640  				L1InclusionBlock: l1F,
   641  				Batch: NewSpanBatch([]*SingularBatch{
   642  					{
   643  						ParentHash:   l2A1.ParentHash,
   644  						EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
   645  						EpochHash:    l2A1.L1Origin.Hash,
   646  						Timestamp:    l2A1.Time,
   647  						Transactions: nil,
   648  					},
   649  				}),
   650  			},
   651  			Expected:    BatchDrop,
   652  			ExpectedLog: "batch was included too late, sequence window expired",
   653  			DeltaTime:   &minTs,
   654  		},
   655  		{
   656  			Name:       "epoch too old, but good parent hash and timestamp", // repeat of now outdated l2A3 data
   657  			L1Blocks:   []eth.L1BlockRef{l1B, l1C, l1D},
   658  			L2SafeHead: l2B0, // we already moved on to B
   659  			Batch: BatchWithL1InclusionBlock{
   660  				L1InclusionBlock: l1C,
   661  				Batch: NewSpanBatch([]*SingularBatch{
   662  					{
   663  						ParentHash:   l2B0.Hash,                          // build on top of safe head to continue
   664  						EpochNum:     rollup.Epoch(l2A3.L1Origin.Number), // epoch A is no longer valid
   665  						EpochHash:    l2A3.L1Origin.Hash,
   666  						Timestamp:    l2B0.Time + defaultConf.BlockTime, // pass the timestamp check to get too epoch check
   667  						Transactions: nil,
   668  					},
   669  					{
   670  						EpochNum:     rollup.Epoch(l1B.Number),
   671  						EpochHash:    l1B.Hash, // pass the l1 origin check
   672  						Timestamp:    l2B0.Time + defaultConf.BlockTime*2,
   673  						Transactions: nil,
   674  					},
   675  				}),
   676  			},
   677  			Expected:    BatchDrop,
   678  			ExpectedLog: "dropped batch, epoch is too old",
   679  			DeltaTime:   &minTs,
   680  		},
   681  		{
   682  			Name:       "insufficient L1 info for eager derivation",
   683  			L1Blocks:   []eth.L1BlockRef{l1A}, // don't know about l1B yet
   684  			L2SafeHead: l2A3,
   685  			Batch: BatchWithL1InclusionBlock{
   686  				L1InclusionBlock: l1C,
   687  				Batch: NewSpanBatch([]*SingularBatch{
   688  					{
   689  						ParentHash:   l2B0.ParentHash,
   690  						EpochNum:     rollup.Epoch(l2B0.L1Origin.Number),
   691  						EpochHash:    l2B0.L1Origin.Hash,
   692  						Timestamp:    l2B0.Time,
   693  						Transactions: nil,
   694  					},
   695  				}),
   696  			},
   697  			Expected:    BatchUndecided,
   698  			ExpectedLog: "eager batch wants to advance epoch, but could not without more L1 blocks",
   699  			DeltaTime:   &minTs,
   700  		},
   701  		{
   702  			Name:       "insufficient L1 info for eager derivation - long span",
   703  			L1Blocks:   []eth.L1BlockRef{l1A}, // don't know about l1B yet
   704  			L2SafeHead: l2A2,
   705  			Batch: BatchWithL1InclusionBlock{
   706  				L1InclusionBlock: l1C,
   707  				Batch: NewSpanBatch([]*SingularBatch{
   708  					{
   709  						ParentHash:   l2A3.ParentHash,
   710  						EpochNum:     rollup.Epoch(l2A3.L1Origin.Number),
   711  						EpochHash:    l2A3.L1Origin.Hash,
   712  						Timestamp:    l2A3.Time,
   713  						Transactions: nil,
   714  					},
   715  					{
   716  						ParentHash:   l2B0.ParentHash,
   717  						EpochNum:     rollup.Epoch(l2B0.L1Origin.Number),
   718  						EpochHash:    l2B0.L1Origin.Hash,
   719  						Timestamp:    l2B0.Time,
   720  						Transactions: nil,
   721  					},
   722  				}),
   723  			},
   724  			Expected:    BatchUndecided,
   725  			ExpectedLog: "need more l1 blocks to check entire origins of span batch",
   726  			DeltaTime:   &minTs,
   727  		},
   728  		{
   729  			Name:       "epoch too new",
   730  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C, l1D},
   731  			L2SafeHead: l2A3,
   732  			Batch: BatchWithL1InclusionBlock{
   733  				L1InclusionBlock: l1D,
   734  				Batch: NewSpanBatch([]*SingularBatch{
   735  					{
   736  						ParentHash:   l2B0.ParentHash,
   737  						EpochNum:     rollup.Epoch(l1C.Number), // invalid, we need to adopt epoch B before C
   738  						EpochHash:    l1C.Hash,
   739  						Timestamp:    l2B0.Time,
   740  						Transactions: nil,
   741  					},
   742  				}),
   743  			},
   744  			Expected:    BatchDrop,
   745  			ExpectedLog: "batch is for future epoch too far ahead, while it has the next timestamp, so it must be invalid",
   746  			DeltaTime:   &minTs,
   747  		},
   748  		{
   749  			Name:       "epoch hash wrong",
   750  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
   751  			L2SafeHead: l2A3,
   752  			Batch: BatchWithL1InclusionBlock{
   753  				L1InclusionBlock: l1C,
   754  				Batch: NewSpanBatch([]*SingularBatch{
   755  					{
   756  						ParentHash:   l2B0.ParentHash,
   757  						EpochNum:     rollup.Epoch(l2B0.L1Origin.Number),
   758  						EpochHash:    l1A.Hash, // invalid, epoch hash should be l1B
   759  						Timestamp:    l2B0.Time,
   760  						Transactions: nil,
   761  					},
   762  				}),
   763  			},
   764  			Expected:    BatchDrop,
   765  			ExpectedLog: "batch is for different L1 chain, epoch hash does not match",
   766  			DeltaTime:   &minTs,
   767  		},
   768  		{
   769  			Name:       "epoch hash wrong - long span",
   770  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
   771  			L2SafeHead: l2A2,
   772  			Batch: BatchWithL1InclusionBlock{
   773  				L1InclusionBlock: l1C,
   774  				Batch: NewSpanBatch([]*SingularBatch{
   775  					{ // valid batch
   776  						ParentHash:   l2A3.ParentHash,
   777  						EpochNum:     rollup.Epoch(l2A3.L1Origin.Number),
   778  						EpochHash:    l1A.Hash,
   779  						Timestamp:    l2A3.Time,
   780  						Transactions: nil,
   781  					},
   782  					{
   783  						ParentHash:   l2B0.ParentHash,
   784  						EpochNum:     rollup.Epoch(l2B0.L1Origin.Number),
   785  						EpochHash:    l1A.Hash, // invalid, epoch hash should be l1B
   786  						Timestamp:    l2B0.Time,
   787  						Transactions: nil,
   788  					},
   789  				}),
   790  			},
   791  			Expected:    BatchDrop,
   792  			ExpectedLog: "batch is for different L1 chain, epoch hash does not match",
   793  			DeltaTime:   &minTs,
   794  		},
   795  		{
   796  			Name:       "sequencer time drift on same epoch with non-empty txs",
   797  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
   798  			L2SafeHead: l2A3,
   799  			Batch: BatchWithL1InclusionBlock{
   800  				L1InclusionBlock: l1B,
   801  				Batch: NewSpanBatch([]*SingularBatch{
   802  					{ // we build l2A4, which has a timestamp of 2*4 = 8 higher than l2A0
   803  						ParentHash:   l2A4.ParentHash,
   804  						EpochNum:     rollup.Epoch(l2A4.L1Origin.Number),
   805  						EpochHash:    l2A4.L1Origin.Hash,
   806  						Timestamp:    l2A4.Time,
   807  						Transactions: []hexutil.Bytes{randTxData},
   808  					},
   809  				}),
   810  			},
   811  			Expected:    BatchDrop,
   812  			ExpectedLog: "batch exceeded sequencer time drift, sequencer must adopt new L1 origin to include transactions again",
   813  			DeltaTime:   &minTs,
   814  		},
   815  		{
   816  			Name:       "sequencer time drift on same epoch with non-empty txs - long span",
   817  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
   818  			L2SafeHead: l2A2,
   819  			Batch: BatchWithL1InclusionBlock{
   820  				L1InclusionBlock: l1B,
   821  				Batch: NewSpanBatch([]*SingularBatch{
   822  					{ // valid batch
   823  						ParentHash:   l2A3.ParentHash,
   824  						EpochNum:     rollup.Epoch(l2A3.L1Origin.Number),
   825  						EpochHash:    l2A3.L1Origin.Hash,
   826  						Timestamp:    l2A3.Time,
   827  						Transactions: []hexutil.Bytes{randTxData},
   828  					},
   829  					{ // we build l2A4, which has a timestamp of 2*4 = 8 higher than l2A0
   830  						ParentHash:   l2A4.ParentHash,
   831  						EpochNum:     rollup.Epoch(l2A4.L1Origin.Number),
   832  						EpochHash:    l2A4.L1Origin.Hash,
   833  						Timestamp:    l2A4.Time,
   834  						Transactions: []hexutil.Bytes{randTxData},
   835  					},
   836  				}),
   837  			},
   838  			Expected:    BatchDrop,
   839  			ExpectedLog: "batch exceeded sequencer time drift, sequencer must adopt new L1 origin to include transactions again",
   840  			DeltaTime:   &minTs,
   841  		},
   842  		{
   843  			Name:       "sequencer time drift on changing epoch with non-empty txs",
   844  			L1Blocks:   []eth.L1BlockRef{l1X, l1Y, l1Z},
   845  			L2SafeHead: l2X0,
   846  			Batch: BatchWithL1InclusionBlock{
   847  				L1InclusionBlock: l1Z,
   848  				Batch: NewSpanBatch([]*SingularBatch{
   849  					{
   850  						ParentHash:   l2Y0.ParentHash,
   851  						EpochNum:     rollup.Epoch(l2Y0.L1Origin.Number),
   852  						EpochHash:    l2Y0.L1Origin.Hash,
   853  						Timestamp:    l2Y0.Time, // valid, but more than 6 ahead of l1Y.Time
   854  						Transactions: []hexutil.Bytes{randTxData},
   855  					},
   856  				}),
   857  			},
   858  			Expected:    BatchDrop,
   859  			ExpectedLog: "batch exceeded sequencer time drift, sequencer must adopt new L1 origin to include transactions again",
   860  			DeltaTime:   &minTs,
   861  		},
   862  		{
   863  			Name:       "sequencer time drift on same epoch with empty txs and late next epoch",
   864  			L1Blocks:   []eth.L1BlockRef{l1A, l1BLate},
   865  			L2SafeHead: l2A3,
   866  			Batch: BatchWithL1InclusionBlock{
   867  				L1InclusionBlock: l1BLate,
   868  				Batch: NewSpanBatch([]*SingularBatch{
   869  					{ // l2A4 time < l1BLate time, so we cannot adopt origin B yet
   870  						ParentHash:   l2A4.ParentHash,
   871  						EpochNum:     rollup.Epoch(l2A4.L1Origin.Number),
   872  						EpochHash:    l2A4.L1Origin.Hash,
   873  						Timestamp:    l2A4.Time,
   874  						Transactions: nil,
   875  					},
   876  				}),
   877  			},
   878  			Expected:  BatchAccept, // accepted because empty & preserving L2 time invariant
   879  			DeltaTime: &minTs,
   880  		},
   881  		{
   882  			Name:       "sequencer time drift on changing epoch with empty txs",
   883  			L1Blocks:   []eth.L1BlockRef{l1X, l1Y, l1Z},
   884  			L2SafeHead: l2X0,
   885  			Batch: BatchWithL1InclusionBlock{
   886  				L1InclusionBlock: l1Z,
   887  				Batch: NewSpanBatch([]*SingularBatch{
   888  					{
   889  						ParentHash:   l2Y0.ParentHash,
   890  						EpochNum:     rollup.Epoch(l2Y0.L1Origin.Number),
   891  						EpochHash:    l2Y0.L1Origin.Hash,
   892  						Timestamp:    l2Y0.Time, // valid, but more than 6 ahead of l1Y.Time
   893  						Transactions: nil,
   894  					},
   895  					{
   896  						ParentHash:   l2Z0.ParentHash,
   897  						EpochNum:     rollup.Epoch(l2Z0.L1Origin.Number),
   898  						EpochHash:    l2Z0.L1Origin.Hash,
   899  						Timestamp:    l2Z0.Time, // valid, but more than 6 ahead of l1Y.Time
   900  						Transactions: nil,
   901  					},
   902  				}),
   903  			},
   904  			Expected:       BatchAccept, // accepted because empty & still advancing epoch
   905  			DeltaTime:      &minTs,
   906  			NotExpectedLog: "continuing with empty batch before late L1 block to preserve L2 time invariant",
   907  		},
   908  		{
   909  			Name:       "sequencer time drift on same epoch with empty txs and no next epoch in sight yet",
   910  			L1Blocks:   []eth.L1BlockRef{l1A},
   911  			L2SafeHead: l2A3,
   912  			Batch: BatchWithL1InclusionBlock{
   913  				L1InclusionBlock: l1B,
   914  				Batch: NewSpanBatch([]*SingularBatch{
   915  					{ // we build l2A4, which has a timestamp of 2*4 = 8 higher than l2A0
   916  						ParentHash:   l2A4.ParentHash,
   917  						EpochNum:     rollup.Epoch(l2A4.L1Origin.Number),
   918  						EpochHash:    l2A4.L1Origin.Hash,
   919  						Timestamp:    l2A4.Time,
   920  						Transactions: nil,
   921  					},
   922  				}),
   923  			},
   924  			Expected:    BatchUndecided, // we have to wait till the next epoch is in sight to check the time
   925  			ExpectedLog: "without the next L1 origin we cannot determine yet if this empty batch that exceeds the time drift is still valid",
   926  			DeltaTime:   &minTs,
   927  		},
   928  		{
   929  			Name:       "sequencer time drift on same epoch with empty txs and no next epoch in sight yet - long span",
   930  			L1Blocks:   []eth.L1BlockRef{l1A},
   931  			L2SafeHead: l2A2,
   932  			Batch: BatchWithL1InclusionBlock{
   933  				L1InclusionBlock: l1B,
   934  				Batch: NewSpanBatch([]*SingularBatch{
   935  					{ // valid batch
   936  						ParentHash:   l2A3.ParentHash,
   937  						EpochNum:     rollup.Epoch(l2A3.L1Origin.Number),
   938  						EpochHash:    l2A3.L1Origin.Hash,
   939  						Timestamp:    l2A3.Time,
   940  						Transactions: nil,
   941  					},
   942  					{ // we build l2A4, which has a timestamp of 2*4 = 8 higher than l2A0
   943  						ParentHash:   l2A4.ParentHash,
   944  						EpochNum:     rollup.Epoch(l2A4.L1Origin.Number),
   945  						EpochHash:    l2A4.L1Origin.Hash,
   946  						Timestamp:    l2A4.Time,
   947  						Transactions: nil,
   948  					},
   949  				}),
   950  			},
   951  			Expected:    BatchUndecided, // we have to wait till the next epoch is in sight to check the time
   952  			ExpectedLog: "without the next L1 origin we cannot determine yet if this empty batch that exceeds the time drift is still valid",
   953  			DeltaTime:   &minTs,
   954  		},
   955  		{
   956  			Name:       "sequencer time drift on same epoch with empty txs and but in-sight epoch that invalidates it",
   957  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C},
   958  			L2SafeHead: l2A3,
   959  			Batch: BatchWithL1InclusionBlock{
   960  				L1InclusionBlock: l1C,
   961  				Batch: NewSpanBatch([]*SingularBatch{
   962  					{ // we build l2A4, which has a timestamp of 2*4 = 8 higher than l2A0
   963  						ParentHash:   l2A4.ParentHash,
   964  						EpochNum:     rollup.Epoch(l2A4.L1Origin.Number),
   965  						EpochHash:    l2A4.L1Origin.Hash,
   966  						Timestamp:    l2A4.Time,
   967  						Transactions: nil,
   968  					},
   969  				}),
   970  			},
   971  			Expected:    BatchDrop, // dropped because it could have advanced the epoch to B
   972  			ExpectedLog: "batch exceeded sequencer time drift without adopting next origin, and next L1 origin would have been valid",
   973  			DeltaTime:   &minTs,
   974  		},
   975  		{
   976  			Name:       "sequencer time drift on same epoch with empty txs and but in-sight epoch that invalidates it - long span",
   977  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C},
   978  			L2SafeHead: l2A2,
   979  			Batch: BatchWithL1InclusionBlock{
   980  				L1InclusionBlock: l1C,
   981  				Batch: NewSpanBatch([]*SingularBatch{
   982  					{ // valid batch
   983  						ParentHash:   l2A3.ParentHash,
   984  						EpochNum:     rollup.Epoch(l2A3.L1Origin.Number),
   985  						EpochHash:    l2A3.L1Origin.Hash,
   986  						Timestamp:    l2A3.Time,
   987  						Transactions: nil,
   988  					},
   989  					{ // we build l2A4, which has a timestamp of 2*4 = 8 higher than l2A0
   990  						ParentHash:   l2A4.ParentHash,
   991  						EpochNum:     rollup.Epoch(l2A4.L1Origin.Number),
   992  						EpochHash:    l2A4.L1Origin.Hash,
   993  						Timestamp:    l2A4.Time,
   994  						Transactions: nil,
   995  					},
   996  				}),
   997  			},
   998  			Expected:    BatchDrop, // dropped because it could have advanced the epoch to B
   999  			ExpectedLog: "batch exceeded sequencer time drift without adopting next origin, and next L1 origin would have been valid",
  1000  			DeltaTime:   &minTs,
  1001  		},
  1002  		{
  1003  			Name:       "empty tx included",
  1004  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1005  			L2SafeHead: l2A0,
  1006  			Batch: BatchWithL1InclusionBlock{
  1007  				L1InclusionBlock: l1B,
  1008  				Batch: NewSpanBatch([]*SingularBatch{
  1009  					{
  1010  						ParentHash: l2A1.ParentHash,
  1011  						EpochNum:   rollup.Epoch(l2A1.L1Origin.Number),
  1012  						EpochHash:  l2A1.L1Origin.Hash,
  1013  						Timestamp:  l2A1.Time,
  1014  						Transactions: []hexutil.Bytes{
  1015  							[]byte{}, // empty tx data
  1016  						},
  1017  					},
  1018  				}),
  1019  			},
  1020  			Expected:    BatchDrop,
  1021  			ExpectedLog: "transaction data must not be empty, but found empty tx",
  1022  			DeltaTime:   &minTs,
  1023  		},
  1024  		{
  1025  			Name:       "deposit tx included",
  1026  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1027  			L2SafeHead: l2A0,
  1028  			Batch: BatchWithL1InclusionBlock{
  1029  				L1InclusionBlock: l1B,
  1030  				Batch: NewSpanBatch([]*SingularBatch{
  1031  					{
  1032  						ParentHash: l2A1.ParentHash,
  1033  						EpochNum:   rollup.Epoch(l2A1.L1Origin.Number),
  1034  						EpochHash:  l2A1.L1Origin.Hash,
  1035  						Timestamp:  l2A1.Time,
  1036  						Transactions: []hexutil.Bytes{
  1037  							[]byte{types.DepositTxType, 0}, // piece of data alike to a deposit
  1038  						},
  1039  					},
  1040  				}),
  1041  			},
  1042  			Expected:    BatchDrop,
  1043  			ExpectedLog: "sequencers may not embed any deposits into batch data, but found tx that has one",
  1044  			DeltaTime:   &minTs,
  1045  		},
  1046  		{
  1047  			Name:       "valid batch same epoch",
  1048  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1049  			L2SafeHead: l2A0,
  1050  			Batch: BatchWithL1InclusionBlock{
  1051  				L1InclusionBlock: l1B,
  1052  				Batch: NewSpanBatch([]*SingularBatch{
  1053  					{
  1054  						ParentHash:   l2A1.ParentHash,
  1055  						EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
  1056  						EpochHash:    l2A1.L1Origin.Hash,
  1057  						Timestamp:    l2A1.Time,
  1058  						Transactions: []hexutil.Bytes{randTxData},
  1059  					},
  1060  				}),
  1061  			},
  1062  			Expected:  BatchAccept,
  1063  			DeltaTime: &minTs,
  1064  		},
  1065  		{
  1066  			Name:       "valid batch changing epoch",
  1067  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C},
  1068  			L2SafeHead: l2A3,
  1069  			Batch: BatchWithL1InclusionBlock{
  1070  				L1InclusionBlock: l1C,
  1071  				Batch: NewSpanBatch([]*SingularBatch{
  1072  					{
  1073  						ParentHash:   l2B0.ParentHash,
  1074  						EpochNum:     rollup.Epoch(l2B0.L1Origin.Number),
  1075  						EpochHash:    l2B0.L1Origin.Hash,
  1076  						Timestamp:    l2B0.Time,
  1077  						Transactions: []hexutil.Bytes{randTxData},
  1078  					},
  1079  				}),
  1080  			},
  1081  			Expected:  BatchAccept,
  1082  			DeltaTime: &minTs,
  1083  		},
  1084  		{
  1085  			Name:       "batch with L2 time before L1 time",
  1086  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C},
  1087  			L2SafeHead: l2A2,
  1088  			Batch: BatchWithL1InclusionBlock{
  1089  				L1InclusionBlock: l1B,
  1090  				Batch: NewSpanBatch([]*SingularBatch{
  1091  					{ // we build l2B0, which starts a new epoch too early
  1092  						ParentHash:   l2A2.Hash,
  1093  						EpochNum:     rollup.Epoch(l2B0.L1Origin.Number),
  1094  						EpochHash:    l2B0.L1Origin.Hash,
  1095  						Timestamp:    l2A2.Time + defaultConf.BlockTime,
  1096  						Transactions: nil,
  1097  					},
  1098  				}),
  1099  			},
  1100  			Expected:    BatchDrop,
  1101  			ExpectedLog: "block timestamp is less than L1 origin timestamp",
  1102  			DeltaTime:   &minTs,
  1103  		},
  1104  		{
  1105  			Name:       "batch with L2 time before L1 time - long span",
  1106  			L1Blocks:   []eth.L1BlockRef{l1A, l1B, l1C},
  1107  			L2SafeHead: l2A1,
  1108  			Batch: BatchWithL1InclusionBlock{
  1109  				L1InclusionBlock: l1B,
  1110  				Batch: NewSpanBatch([]*SingularBatch{
  1111  					{ // valid batch
  1112  						ParentHash:   l2A1.Hash,
  1113  						EpochNum:     rollup.Epoch(l2A2.L1Origin.Number),
  1114  						EpochHash:    l2A2.L1Origin.Hash,
  1115  						Timestamp:    l2A2.Time,
  1116  						Transactions: nil,
  1117  					},
  1118  					{ // we build l2B0, which starts a new epoch too early
  1119  						ParentHash:   l2A2.Hash,
  1120  						EpochNum:     rollup.Epoch(l2B0.L1Origin.Number),
  1121  						EpochHash:    l2B0.L1Origin.Hash,
  1122  						Timestamp:    l2A2.Time + defaultConf.BlockTime,
  1123  						Transactions: nil,
  1124  					},
  1125  				}),
  1126  			},
  1127  			Expected:    BatchDrop,
  1128  			ExpectedLog: "block timestamp is less than L1 origin timestamp",
  1129  			DeltaTime:   &minTs,
  1130  		},
  1131  		{
  1132  			Name:       "valid overlapping batch",
  1133  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1134  			L2SafeHead: l2A2,
  1135  			Batch: BatchWithL1InclusionBlock{
  1136  				L1InclusionBlock: l1B,
  1137  				Batch: NewSpanBatch([]*SingularBatch{
  1138  					{
  1139  						ParentHash:   l2A1.Hash,
  1140  						EpochNum:     rollup.Epoch(l2A2.L1Origin.Number),
  1141  						EpochHash:    l2A2.L1Origin.Hash,
  1142  						Timestamp:    l2A2.Time,
  1143  						Transactions: nil,
  1144  					},
  1145  					{
  1146  						ParentHash:   l2A2.Hash,
  1147  						EpochNum:     rollup.Epoch(l2A3.L1Origin.Number),
  1148  						EpochHash:    l2A3.L1Origin.Hash,
  1149  						Timestamp:    l2A3.Time,
  1150  						Transactions: nil,
  1151  					},
  1152  				}),
  1153  			},
  1154  			Expected:  BatchAccept,
  1155  			DeltaTime: &minTs,
  1156  		},
  1157  		{
  1158  			Name:       "longer overlapping batch",
  1159  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1160  			L2SafeHead: l2A2,
  1161  			Batch: BatchWithL1InclusionBlock{
  1162  				L1InclusionBlock: l1B,
  1163  				Batch: NewSpanBatch([]*SingularBatch{
  1164  					{
  1165  						ParentHash:   l2A0.Hash,
  1166  						EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
  1167  						EpochHash:    l2A1.L1Origin.Hash,
  1168  						Timestamp:    l2A1.Time,
  1169  						Transactions: nil,
  1170  					},
  1171  					{
  1172  						ParentHash:   l2A1.Hash,
  1173  						EpochNum:     rollup.Epoch(l2A2.L1Origin.Number),
  1174  						EpochHash:    l2A2.L1Origin.Hash,
  1175  						Timestamp:    l2A2.Time,
  1176  						Transactions: nil,
  1177  					},
  1178  					{
  1179  						ParentHash:   l2A2.Hash,
  1180  						EpochNum:     rollup.Epoch(l2A3.L1Origin.Number),
  1181  						EpochHash:    l2A3.L1Origin.Hash,
  1182  						Timestamp:    l2A3.Time,
  1183  						Transactions: nil,
  1184  					},
  1185  				}),
  1186  			},
  1187  			Expected:  BatchAccept,
  1188  			DeltaTime: &minTs,
  1189  		},
  1190  		{
  1191  			Name:       "fully overlapping batch",
  1192  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1193  			L2SafeHead: l2A2,
  1194  			Batch: BatchWithL1InclusionBlock{
  1195  				L1InclusionBlock: l1B,
  1196  				Batch: NewSpanBatch([]*SingularBatch{
  1197  					{
  1198  						ParentHash:   l2A0.Hash,
  1199  						EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
  1200  						EpochHash:    l2A1.L1Origin.Hash,
  1201  						Timestamp:    l2A1.Time,
  1202  						Transactions: nil,
  1203  					},
  1204  					{
  1205  						ParentHash:   l2A1.Hash,
  1206  						EpochNum:     rollup.Epoch(l2A2.L1Origin.Number),
  1207  						EpochHash:    l2A2.L1Origin.Hash,
  1208  						Timestamp:    l2A2.Time,
  1209  						Transactions: nil,
  1210  					},
  1211  				}),
  1212  			},
  1213  			Expected:    BatchDrop,
  1214  			ExpectedLog: "span batch has no new blocks after safe head",
  1215  			DeltaTime:   &minTs,
  1216  		},
  1217  		{
  1218  			Name:       "overlapping batch with invalid parent hash",
  1219  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1220  			L2SafeHead: l2A2,
  1221  			Batch: BatchWithL1InclusionBlock{
  1222  				L1InclusionBlock: l1B,
  1223  				Batch: NewSpanBatch([]*SingularBatch{
  1224  					{
  1225  						ParentHash:   l2A0.Hash,
  1226  						EpochNum:     rollup.Epoch(l2A2.L1Origin.Number),
  1227  						EpochHash:    l2A2.L1Origin.Hash,
  1228  						Timestamp:    l2A2.Time,
  1229  						Transactions: nil,
  1230  					},
  1231  					{
  1232  						ParentHash:   l2A2.Hash,
  1233  						EpochNum:     rollup.Epoch(l2A3.L1Origin.Number),
  1234  						EpochHash:    l2A3.L1Origin.Hash,
  1235  						Timestamp:    l2A3.Time,
  1236  						Transactions: nil,
  1237  					},
  1238  				}),
  1239  			},
  1240  			Expected:    BatchDrop,
  1241  			ExpectedLog: "ignoring batch with mismatching parent hash",
  1242  			DeltaTime:   &minTs,
  1243  		},
  1244  		{
  1245  			Name:       "overlapping batch with invalid origin number",
  1246  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1247  			L2SafeHead: l2A2,
  1248  			Batch: BatchWithL1InclusionBlock{
  1249  				L1InclusionBlock: l1B,
  1250  				Batch: NewSpanBatch([]*SingularBatch{
  1251  					{
  1252  						ParentHash:   l2A1.Hash,
  1253  						EpochNum:     rollup.Epoch(l2A2.L1Origin.Number) + 1,
  1254  						EpochHash:    l2A2.L1Origin.Hash,
  1255  						Timestamp:    l2A2.Time,
  1256  						Transactions: nil,
  1257  					},
  1258  					{
  1259  						ParentHash:   l2A2.Hash,
  1260  						EpochNum:     rollup.Epoch(l2A3.L1Origin.Number),
  1261  						EpochHash:    l2A3.L1Origin.Hash,
  1262  						Timestamp:    l2A3.Time,
  1263  						Transactions: nil,
  1264  					},
  1265  				}),
  1266  			},
  1267  			Expected:    BatchDrop,
  1268  			ExpectedLog: "overlapped block's L1 origin number does not match",
  1269  			DeltaTime:   &minTs,
  1270  		},
  1271  		{
  1272  			Name:       "overlapping batch with invalid tx",
  1273  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1274  			L2SafeHead: l2A2,
  1275  			Batch: BatchWithL1InclusionBlock{
  1276  				L1InclusionBlock: l1B,
  1277  				Batch: NewSpanBatch([]*SingularBatch{
  1278  					{
  1279  						ParentHash:   l2A1.Hash,
  1280  						EpochNum:     rollup.Epoch(l2A2.L1Origin.Number),
  1281  						EpochHash:    l2A2.L1Origin.Hash,
  1282  						Timestamp:    l2A2.Time,
  1283  						Transactions: []hexutil.Bytes{randTxData},
  1284  					},
  1285  					{
  1286  						ParentHash:   l2A2.Hash,
  1287  						EpochNum:     rollup.Epoch(l2A3.L1Origin.Number),
  1288  						EpochHash:    l2A3.L1Origin.Hash,
  1289  						Timestamp:    l2A3.Time,
  1290  						Transactions: nil,
  1291  					},
  1292  				}),
  1293  			},
  1294  			Expected:    BatchDrop,
  1295  			ExpectedLog: "overlapped block's tx count does not match",
  1296  			DeltaTime:   &minTs,
  1297  		},
  1298  		{
  1299  			Name:       "overlapping batch l2 fetcher error",
  1300  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1301  			L2SafeHead: l2A1,
  1302  			Batch: BatchWithL1InclusionBlock{
  1303  				L1InclusionBlock: l1B,
  1304  				Batch: NewSpanBatch([]*SingularBatch{
  1305  					{
  1306  						ParentHash:   l2A0.ParentHash,
  1307  						EpochNum:     rollup.Epoch(l2A0.L1Origin.Number),
  1308  						EpochHash:    l2A0.L1Origin.Hash,
  1309  						Timestamp:    l2A0.Time,
  1310  						Transactions: nil,
  1311  					},
  1312  					{
  1313  						ParentHash:   l2A0.Hash,
  1314  						EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
  1315  						EpochHash:    l2A1.L1Origin.Hash,
  1316  						Timestamp:    l2A1.Time,
  1317  						Transactions: nil,
  1318  					},
  1319  					{
  1320  						ParentHash:   l2A1.Hash,
  1321  						EpochNum:     rollup.Epoch(l2A2.L1Origin.Number),
  1322  						EpochHash:    l2A2.L1Origin.Hash,
  1323  						Timestamp:    l2A2.Time,
  1324  						Transactions: nil,
  1325  					},
  1326  				}),
  1327  			},
  1328  			Expected:    BatchUndecided,
  1329  			ExpectedLog: "failed to fetch L2 block",
  1330  			DeltaTime:   &minTs,
  1331  		},
  1332  		{
  1333  			Name:       "short block time",
  1334  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1335  			L2SafeHead: l2A0,
  1336  			Batch: BatchWithL1InclusionBlock{
  1337  				L1InclusionBlock: l1B,
  1338  				Batch: NewSpanBatch([]*SingularBatch{
  1339  					{
  1340  						ParentHash:   l2A0.Hash,
  1341  						EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
  1342  						EpochHash:    l2A1.L1Origin.Hash,
  1343  						Timestamp:    l2A0.Time + 1,
  1344  						Transactions: nil,
  1345  					},
  1346  					{
  1347  						ParentHash:   l2A1.Hash,
  1348  						EpochNum:     rollup.Epoch(l2A2.L1Origin.Number),
  1349  						EpochHash:    l2A2.L1Origin.Hash,
  1350  						Timestamp:    l2A1.Time + 1,
  1351  						Transactions: nil,
  1352  					},
  1353  				}),
  1354  			},
  1355  			Expected:    BatchDrop,
  1356  			ExpectedLog: "batch has misaligned timestamp, block time is too short",
  1357  			DeltaTime:   &minTs,
  1358  		},
  1359  		{
  1360  			Name:       "misaligned batch",
  1361  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1362  			L2SafeHead: l2A0,
  1363  			Batch: BatchWithL1InclusionBlock{
  1364  				L1InclusionBlock: l1B,
  1365  				Batch: NewSpanBatch([]*SingularBatch{
  1366  					{
  1367  						ParentHash:   l2A0.Hash,
  1368  						EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
  1369  						EpochHash:    l2A1.L1Origin.Hash,
  1370  						Timestamp:    l2A0.Time - 1,
  1371  						Transactions: nil,
  1372  					},
  1373  					{
  1374  						ParentHash:   l2A1.Hash,
  1375  						EpochNum:     rollup.Epoch(l2A2.L1Origin.Number),
  1376  						EpochHash:    l2A2.L1Origin.Hash,
  1377  						Timestamp:    l2A1.Time,
  1378  						Transactions: nil,
  1379  					},
  1380  				}),
  1381  			},
  1382  			Expected:    BatchDrop,
  1383  			ExpectedLog: "batch has misaligned timestamp, not overlapped exactly",
  1384  			DeltaTime:   &minTs,
  1385  		},
  1386  		{
  1387  			Name:       "failed to fetch overlapping block payload",
  1388  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1389  			L2SafeHead: l2A3,
  1390  			Batch: BatchWithL1InclusionBlock{
  1391  				L1InclusionBlock: l1B,
  1392  				Batch: NewSpanBatch([]*SingularBatch{
  1393  					{
  1394  						ParentHash:   l2A2.Hash,
  1395  						EpochNum:     rollup.Epoch(l2A3.L1Origin.Number),
  1396  						EpochHash:    l2A3.L1Origin.Hash,
  1397  						Timestamp:    l2A3.Time,
  1398  						Transactions: nil,
  1399  					},
  1400  					{
  1401  						ParentHash:   l2A3.Hash,
  1402  						EpochNum:     rollup.Epoch(l2B0.L1Origin.Number),
  1403  						EpochHash:    l2B0.L1Origin.Hash,
  1404  						Timestamp:    l2B0.Time,
  1405  						Transactions: nil,
  1406  					},
  1407  				}),
  1408  			},
  1409  			Expected:    BatchUndecided,
  1410  			ExpectedLog: "failed to fetch L2 block payload",
  1411  			DeltaTime:   &minTs,
  1412  		},
  1413  		{
  1414  			Name:       "singular batch before hard fork",
  1415  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1416  			L2SafeHead: l2A0,
  1417  			Batch: BatchWithL1InclusionBlock{
  1418  				L1InclusionBlock: l1B,
  1419  				Batch: &SingularBatch{
  1420  					ParentHash:   l2A1.ParentHash,
  1421  					EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
  1422  					EpochHash:    l2A1.L1Origin.Hash,
  1423  					Timestamp:    l2A1.Time,
  1424  					Transactions: []hexutil.Bytes{randTxData},
  1425  				},
  1426  			},
  1427  			DeltaTime: &l1B.Time,
  1428  			Expected:  BatchAccept,
  1429  		},
  1430  		{
  1431  			Name:       "span batch before hard fork",
  1432  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1433  			L2SafeHead: l2A0,
  1434  			Batch: BatchWithL1InclusionBlock{
  1435  				L1InclusionBlock: l1B,
  1436  				Batch: NewSpanBatch([]*SingularBatch{
  1437  					{
  1438  						ParentHash:   l2A1.ParentHash,
  1439  						EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
  1440  						EpochHash:    l2A1.L1Origin.Hash,
  1441  						Timestamp:    l2A1.Time,
  1442  						Transactions: []hexutil.Bytes{randTxData},
  1443  					},
  1444  				}),
  1445  			},
  1446  			DeltaTime:   &l1B.Time,
  1447  			Expected:    BatchDrop,
  1448  			ExpectedLog: "received SpanBatch with L1 origin before Delta hard fork",
  1449  		},
  1450  		{
  1451  			Name:       "singular batch after hard fork",
  1452  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1453  			L2SafeHead: l2A0,
  1454  			Batch: BatchWithL1InclusionBlock{
  1455  				L1InclusionBlock: l1B,
  1456  				Batch: &SingularBatch{
  1457  					ParentHash:   l2A1.ParentHash,
  1458  					EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
  1459  					EpochHash:    l2A1.L1Origin.Hash,
  1460  					Timestamp:    l2A1.Time,
  1461  					Transactions: []hexutil.Bytes{randTxData},
  1462  				},
  1463  			},
  1464  			DeltaTime: &l1A.Time,
  1465  			Expected:  BatchAccept,
  1466  		},
  1467  		{
  1468  			Name:       "span batch after hard fork",
  1469  			L1Blocks:   []eth.L1BlockRef{l1A, l1B},
  1470  			L2SafeHead: l2A0,
  1471  			Batch: BatchWithL1InclusionBlock{
  1472  				L1InclusionBlock: l1B,
  1473  				Batch: NewSpanBatch([]*SingularBatch{
  1474  					{
  1475  						ParentHash:   l2A1.ParentHash,
  1476  						EpochNum:     rollup.Epoch(l2A1.L1Origin.Number),
  1477  						EpochHash:    l2A1.L1Origin.Hash,
  1478  						Timestamp:    l2A1.Time,
  1479  						Transactions: []hexutil.Bytes{randTxData},
  1480  					},
  1481  				}),
  1482  			},
  1483  			DeltaTime: &l1A.Time,
  1484  			Expected:  BatchAccept,
  1485  		},
  1486  	}
  1487  
  1488  	// Log level can be increased for debugging purposes
  1489  	logger, logs := testlog.CaptureLogger(t, log.LevelDebug)
  1490  
  1491  	l2Client := testutils.MockL2Client{}
  1492  	var nilErr error
  1493  	tempErr := errors.New("temp error")
  1494  	// will return an error for block #99 (parent of l2A0)
  1495  	l2Client.Mock.On("L2BlockRefByNumber", l2A0.Number-1).Return(eth.L2BlockRef{}, &tempErr)
  1496  	// will return an error for l2A3
  1497  	l2Client.Mock.On("PayloadByNumber", l2A3.Number).Return(&eth.ExecutionPayloadEnvelope{}, &tempErr)
  1498  
  1499  	// make payloads for L2 blocks and set as expected return value of MockL2Client
  1500  	for _, l2Block := range []eth.L2BlockRef{l2A0, l2A1, l2A2, l2B0} {
  1501  		l2Client.ExpectL2BlockRefByNumber(l2Block.Number, l2Block, nil)
  1502  		txData := l1InfoDepositTx(t, l2Block.L1Origin.Number)
  1503  		payload := eth.ExecutionPayloadEnvelope{
  1504  			ExecutionPayload: &eth.ExecutionPayload{
  1505  				ParentHash:   l2Block.ParentHash,
  1506  				BlockNumber:  hexutil.Uint64(l2Block.Number),
  1507  				Timestamp:    hexutil.Uint64(l2Block.Time),
  1508  				BlockHash:    l2Block.Hash,
  1509  				Transactions: []hexutil.Bytes{txData},
  1510  			},
  1511  		}
  1512  		l2Client.Mock.On("L2BlockRefByNumber", l2Block.Number).Return(l2Block, &nilErr)
  1513  		l2Client.Mock.On("PayloadByNumber", l2Block.Number).Return(&payload, &nilErr)
  1514  	}
  1515  
  1516  	runTestCase := func(t *testing.T, testCase ValidBatchTestCase) {
  1517  		ctx := context.Background()
  1518  		rcfg := defaultConf
  1519  		if testCase.DeltaTime != nil {
  1520  			rcfg.DeltaTime = testCase.DeltaTime
  1521  		}
  1522  		validity := CheckBatch(ctx, &rcfg, logger, testCase.L1Blocks, testCase.L2SafeHead, &testCase.Batch, &l2Client)
  1523  		require.Equal(t, testCase.Expected, validity, "batch check must return expected validity level")
  1524  		if expLog := testCase.ExpectedLog; expLog != "" {
  1525  			// Check if ExpectedLog is contained in the log buffer
  1526  			containsFilter := testlog.NewMessageContainsFilter(expLog)
  1527  			if l := logs.FindLog(containsFilter); l == nil {
  1528  				t.Errorf("Expected log message was not logged: %q", expLog)
  1529  			}
  1530  		}
  1531  		if notExpLog := testCase.NotExpectedLog; notExpLog != "" {
  1532  			// Check if NotExpectedLog is contained in the log buffer
  1533  			containsFilter := testlog.NewMessageContainsFilter(notExpLog)
  1534  			if l := logs.FindLog(containsFilter); l != nil {
  1535  				t.Errorf("Unexpected log message containing %q was logged: %q", notExpLog, l.Message)
  1536  			}
  1537  		}
  1538  		logs.Clear()
  1539  	}
  1540  
  1541  	// Run singular batch test cases
  1542  	for _, testCase := range singularBatchTestCases {
  1543  		t.Run("singular_"+testCase.Name, func(t *testing.T) {
  1544  			runTestCase(t, testCase)
  1545  		})
  1546  	}
  1547  
  1548  	// Run span batch test cases
  1549  	for _, testCase := range spanBatchTestCases {
  1550  		t.Run("span_"+testCase.Name, func(t *testing.T) {
  1551  			runTestCase(t, testCase)
  1552  		})
  1553  	}
  1554  
  1555  	// ====== Test different TX for overlapping batches ======
  1556  	l2Client.ExpectL2BlockRefByNumber(l2B1.Number, l2B1, nil)
  1557  	txData := l1InfoDepositTx(t, l2B1.L1Origin.Number)
  1558  	randTx = testutils.RandomTx(rng, new(big.Int).SetUint64(rng.Uint64()), signer)
  1559  	randTxData, _ = randTx.MarshalBinary()
  1560  	payload := eth.ExecutionPayloadEnvelope{
  1561  		ExecutionPayload: &eth.ExecutionPayload{
  1562  			ParentHash:   l2B0.Hash,
  1563  			BlockNumber:  hexutil.Uint64(l2B1.Number),
  1564  			Timestamp:    hexutil.Uint64(l2B1.Time),
  1565  			BlockHash:    l2B1.Hash,
  1566  			Transactions: []hexutil.Bytes{txData, randTxData},
  1567  		},
  1568  	}
  1569  	l2Client.Mock.On("PayloadByNumber", l2B1.Number).Return(&payload, &nilErr).Once()
  1570  
  1571  	randTx = testutils.RandomTx(rng, new(big.Int).SetUint64(rng.Uint64()), signer)
  1572  	randTxData, _ = randTx.MarshalBinary()
  1573  	differentTxtestCase := ValidBatchTestCase{
  1574  		Name:       "different_tx_overlapping_batch",
  1575  		L1Blocks:   []eth.L1BlockRef{l1B},
  1576  		L2SafeHead: l2B1,
  1577  		Batch: BatchWithL1InclusionBlock{
  1578  			L1InclusionBlock: l1B,
  1579  			Batch: NewSpanBatch([]*SingularBatch{
  1580  				{
  1581  					ParentHash:   l2B0.Hash,
  1582  					EpochNum:     rollup.Epoch(l2B1.L1Origin.Number),
  1583  					EpochHash:    l2B1.L1Origin.Hash,
  1584  					Timestamp:    l2B1.Time,
  1585  					Transactions: []hexutil.Bytes{randTxData}, // Random generated TX that does not match overlapping block
  1586  				},
  1587  				{
  1588  					ParentHash:   l2B1.Hash,
  1589  					EpochNum:     rollup.Epoch(l2B2.L1Origin.Number),
  1590  					EpochHash:    l2B2.L1Origin.Hash,
  1591  					Timestamp:    l2B2.Time,
  1592  					Transactions: nil,
  1593  				},
  1594  			}),
  1595  		},
  1596  		Expected:    BatchDrop,
  1597  		ExpectedLog: "overlapped block's transaction does not match",
  1598  		DeltaTime:   &minTs,
  1599  	}
  1600  
  1601  	t.Run(differentTxtestCase.Name, func(t *testing.T) {
  1602  		runTestCase(t, differentTxtestCase)
  1603  	})
  1604  
  1605  	// ====== Test invalid TX for overlapping batches ======
  1606  	payload = eth.ExecutionPayloadEnvelope{
  1607  		ExecutionPayload: &eth.ExecutionPayload{
  1608  			ParentHash:  l2B0.Hash,
  1609  			BlockNumber: hexutil.Uint64(l2B1.Number),
  1610  			Timestamp:   hexutil.Uint64(l2B1.Time),
  1611  			BlockHash:   l2B1.Hash,
  1612  			// First TX is not a deposit TX. it will make error when extracting L2BlockRef from the payload
  1613  			Transactions: []hexutil.Bytes{randTxData},
  1614  		},
  1615  	}
  1616  	l2Client.Mock.On("PayloadByNumber", l2B1.Number).Return(&payload, &nilErr).Once()
  1617  
  1618  	invalidTxTestCase := ValidBatchTestCase{
  1619  		Name:       "invalid_tx_overlapping_batch",
  1620  		L1Blocks:   []eth.L1BlockRef{l1B},
  1621  		L2SafeHead: l2B1,
  1622  		Batch: BatchWithL1InclusionBlock{
  1623  			L1InclusionBlock: l1B,
  1624  			Batch: NewSpanBatch([]*SingularBatch{
  1625  				{
  1626  					ParentHash:   l2B0.Hash,
  1627  					EpochNum:     rollup.Epoch(l2B1.L1Origin.Number),
  1628  					EpochHash:    l2B1.L1Origin.Hash,
  1629  					Timestamp:    l2B1.Time,
  1630  					Transactions: []hexutil.Bytes{randTxData},
  1631  				},
  1632  				{
  1633  					ParentHash:   l2B1.Hash,
  1634  					EpochNum:     rollup.Epoch(l2B2.L1Origin.Number),
  1635  					EpochHash:    l2B2.L1Origin.Hash,
  1636  					Timestamp:    l2B2.Time,
  1637  					Transactions: nil,
  1638  				},
  1639  			}),
  1640  		},
  1641  		Expected:    BatchDrop,
  1642  		ExpectedLog: "failed to extract L2BlockRef from execution payload",
  1643  		DeltaTime:   &minTs,
  1644  	}
  1645  
  1646  	t.Run(invalidTxTestCase.Name, func(t *testing.T) {
  1647  		runTestCase(t, invalidTxTestCase)
  1648  	})
  1649  }