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

     1  package derive
     2  
     3  import (
     4  	"bytes"
     5  	"math/big"
     6  	"math/rand"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/require"
    10  
    11  	"github.com/ethereum/go-ethereum/common"
    12  	"github.com/ethereum/go-ethereum/common/hexutil"
    13  	"github.com/ethereum/go-ethereum/core/types"
    14  	"github.com/ethereum/go-ethereum/rlp"
    15  
    16  	"github.com/ethereum-optimism/optimism/op-node/rollup"
    17  	"github.com/ethereum-optimism/optimism/op-service/eth"
    18  	"github.com/ethereum-optimism/optimism/op-service/testutils"
    19  )
    20  
    21  func RandomRawSpanBatch(rng *rand.Rand, chainId *big.Int) *RawSpanBatch {
    22  	blockCount := uint64(4 + rng.Int()&0xFF) // at least 4
    23  	originBits := new(big.Int)
    24  	for i := 0; i < int(blockCount); i++ {
    25  		bit := uint(0)
    26  		if testutils.RandomBool(rng) {
    27  			bit = uint(1)
    28  		}
    29  		originBits.SetBit(originBits, i, bit)
    30  	}
    31  	var blockTxCounts []uint64
    32  	totalblockTxCounts := uint64(0)
    33  	for i := 0; i < int(blockCount); i++ {
    34  		blockTxCount := 1 + uint64(rng.Intn(16))
    35  		blockTxCounts = append(blockTxCounts, blockTxCount)
    36  		totalblockTxCounts += blockTxCount
    37  	}
    38  	londonSigner := types.NewLondonSigner(chainId)
    39  	var txs [][]byte
    40  	for i := 0; i < int(totalblockTxCounts); i++ {
    41  		var tx *types.Transaction
    42  		switch i % 4 {
    43  		case 0:
    44  			tx = testutils.RandomLegacyTx(rng, types.HomesteadSigner{})
    45  		case 1:
    46  			tx = testutils.RandomLegacyTx(rng, londonSigner)
    47  		case 2:
    48  			tx = testutils.RandomAccessListTx(rng, londonSigner)
    49  		case 3:
    50  			tx = testutils.RandomDynamicFeeTx(rng, londonSigner)
    51  		}
    52  		rawTx, err := tx.MarshalBinary()
    53  		if err != nil {
    54  			panic("MarshalBinary:" + err.Error())
    55  		}
    56  		txs = append(txs, rawTx)
    57  	}
    58  	spanBatchTxs, err := newSpanBatchTxs(txs, chainId)
    59  	if err != nil {
    60  		panic(err.Error())
    61  	}
    62  	rawSpanBatch := RawSpanBatch{
    63  		spanBatchPrefix: spanBatchPrefix{
    64  			relTimestamp:  uint64(rng.Uint32()),
    65  			l1OriginNum:   rng.Uint64(),
    66  			parentCheck:   [20]byte(testutils.RandomData(rng, 20)),
    67  			l1OriginCheck: [20]byte(testutils.RandomData(rng, 20)),
    68  		},
    69  		spanBatchPayload: spanBatchPayload{
    70  			blockCount:    blockCount,
    71  			originBits:    originBits,
    72  			blockTxCounts: blockTxCounts,
    73  			txs:           spanBatchTxs,
    74  		},
    75  	}
    76  	return &rawSpanBatch
    77  }
    78  
    79  func RandomSingularBatch(rng *rand.Rand, txCount int, chainID *big.Int) *SingularBatch {
    80  	signer := types.NewLondonSigner(chainID)
    81  	baseFee := big.NewInt(rng.Int63n(300_000_000_000))
    82  	txsEncoded := make([]hexutil.Bytes, 0, txCount)
    83  	// force each tx to have equal chainID
    84  	for i := 0; i < txCount; i++ {
    85  		tx := testutils.RandomTx(rng, baseFee, signer)
    86  		txEncoded, err := tx.MarshalBinary()
    87  		if err != nil {
    88  			panic("tx Marshal binary" + err.Error())
    89  		}
    90  		txsEncoded = append(txsEncoded, hexutil.Bytes(txEncoded))
    91  	}
    92  	return &SingularBatch{
    93  		ParentHash:   testutils.RandomHash(rng),
    94  		EpochNum:     rollup.Epoch(1 + rng.Int63n(100_000_000)),
    95  		EpochHash:    testutils.RandomHash(rng),
    96  		Timestamp:    uint64(rng.Int63n(2_000_000_000)),
    97  		Transactions: txsEncoded,
    98  	}
    99  }
   100  
   101  func RandomValidConsecutiveSingularBatches(rng *rand.Rand, chainID *big.Int) []*SingularBatch {
   102  	blockCount := 2 + rng.Intn(128)
   103  	l2BlockTime := uint64(2)
   104  
   105  	var singularBatches []*SingularBatch
   106  	for i := 0; i < blockCount; i++ {
   107  		singularBatch := RandomSingularBatch(rng, 1+rng.Intn(8), chainID)
   108  		singularBatches = append(singularBatches, singularBatch)
   109  	}
   110  	l1BlockNum := rng.Uint64()
   111  	// make sure oldest timestamp is large enough
   112  	singularBatches[0].Timestamp += 256
   113  	for i := 0; i < blockCount; i++ {
   114  		originChangedBit := rng.Intn(2)
   115  		if originChangedBit == 1 {
   116  			l1BlockNum++
   117  			singularBatches[i].EpochHash = testutils.RandomHash(rng)
   118  		} else if i > 0 {
   119  			singularBatches[i].EpochHash = singularBatches[i-1].EpochHash
   120  		}
   121  		singularBatches[i].EpochNum = rollup.Epoch(l1BlockNum)
   122  		if i > 0 {
   123  			singularBatches[i].Timestamp = singularBatches[i-1].Timestamp + l2BlockTime
   124  		}
   125  	}
   126  	return singularBatches
   127  }
   128  
   129  func mockL1Origin(rng *rand.Rand, rawSpanBatch *RawSpanBatch, singularBatches []*SingularBatch) []eth.L1BlockRef {
   130  	safeHeadOrigin := testutils.RandomBlockRef(rng)
   131  	safeHeadOrigin.Hash = singularBatches[0].EpochHash
   132  	safeHeadOrigin.Number = uint64(singularBatches[0].EpochNum)
   133  
   134  	l1Origins := []eth.L1BlockRef{safeHeadOrigin}
   135  	originBitSum := uint64(0)
   136  	for i := 0; i < int(rawSpanBatch.blockCount); i++ {
   137  		if rawSpanBatch.originBits.Bit(i) == 1 {
   138  			l1Origin := testutils.NextRandomRef(rng, l1Origins[originBitSum])
   139  			originBitSum++
   140  			l1Origin.Hash = singularBatches[i].EpochHash
   141  			l1Origin.Number = uint64(singularBatches[i].EpochNum)
   142  			l1Origins = append(l1Origins, l1Origin)
   143  		}
   144  	}
   145  	return l1Origins
   146  }
   147  
   148  func TestBatchRoundTrip(t *testing.T) {
   149  	rng := rand.New(rand.NewSource(0xdeadbeef))
   150  	blockTime := uint64(2)
   151  	genesisTimestamp := uint64(0)
   152  	chainID := new(big.Int).SetUint64(rng.Uint64())
   153  
   154  	batches := []*BatchData{
   155  		NewBatchData(
   156  			&SingularBatch{
   157  				ParentHash:   common.Hash{},
   158  				EpochNum:     0,
   159  				Timestamp:    0,
   160  				Transactions: []hexutil.Bytes{},
   161  			},
   162  		),
   163  		NewBatchData(
   164  			&SingularBatch{
   165  				ParentHash:   common.Hash{31: 0x42},
   166  				EpochNum:     1,
   167  				Timestamp:    1647026951,
   168  				Transactions: []hexutil.Bytes{[]byte{0, 0, 0}, []byte{0x76, 0xfd, 0x7c}},
   169  			},
   170  		),
   171  		NewBatchData(RandomSingularBatch(rng, 5, chainID)),
   172  		NewBatchData(RandomSingularBatch(rng, 7, chainID)),
   173  		NewBatchData(RandomRawSpanBatch(rng, chainID)),
   174  		NewBatchData(RandomRawSpanBatch(rng, chainID)),
   175  		NewBatchData(RandomRawSpanBatch(rng, chainID)),
   176  	}
   177  
   178  	for i, batch := range batches {
   179  		enc, err := batch.MarshalBinary()
   180  		require.NoError(t, err)
   181  		var dec BatchData
   182  		err = dec.UnmarshalBinary(enc)
   183  		require.NoError(t, err)
   184  		if dec.GetBatchType() == SpanBatchType {
   185  			_, err := DeriveSpanBatch(&dec, blockTime, genesisTimestamp, chainID)
   186  			require.NoError(t, err)
   187  		}
   188  		require.Equal(t, batch, &dec, "Batch not equal test case %v", i)
   189  	}
   190  }
   191  
   192  func TestBatchRoundTripRLP(t *testing.T) {
   193  	rng := rand.New(rand.NewSource(0xbeefdead))
   194  	blockTime := uint64(2)
   195  	genesisTimestamp := uint64(0)
   196  	chainID := new(big.Int).SetUint64(rng.Uint64())
   197  
   198  	batches := []*BatchData{
   199  		NewBatchData(
   200  			&SingularBatch{
   201  				ParentHash:   common.Hash{},
   202  				EpochNum:     0,
   203  				Timestamp:    0,
   204  				Transactions: []hexutil.Bytes{},
   205  			},
   206  		),
   207  		NewBatchData(
   208  			&SingularBatch{
   209  				ParentHash:   common.Hash{31: 0x42},
   210  				EpochNum:     1,
   211  				Timestamp:    1647026951,
   212  				Transactions: []hexutil.Bytes{[]byte{0, 0, 0}, []byte{0x76, 0xfd, 0x7c}},
   213  			},
   214  		),
   215  		NewBatchData(RandomSingularBatch(rng, 5, chainID)),
   216  		NewBatchData(RandomSingularBatch(rng, 7, chainID)),
   217  		NewBatchData(RandomRawSpanBatch(rng, chainID)),
   218  		NewBatchData(RandomRawSpanBatch(rng, chainID)),
   219  		NewBatchData(RandomRawSpanBatch(rng, chainID)),
   220  	}
   221  
   222  	for i, batch := range batches {
   223  		var buf bytes.Buffer
   224  		err := batch.EncodeRLP(&buf)
   225  		require.NoError(t, err)
   226  		result := buf.Bytes()
   227  		var dec BatchData
   228  		r := bytes.NewReader(result)
   229  		s := rlp.NewStream(r, 0)
   230  		err = dec.DecodeRLP(s)
   231  		require.NoError(t, err)
   232  		if dec.GetBatchType() == SpanBatchType {
   233  			_, err = DeriveSpanBatch(&dec, blockTime, genesisTimestamp, chainID)
   234  			require.NoError(t, err)
   235  		}
   236  		require.Equal(t, batch, &dec, "Batch not equal test case %v", i)
   237  	}
   238  }