batch_test.go 6.19 KB
Newer Older
1 2 3
package derive

import (
4 5 6
	"bytes"
	"math/big"
	"math/rand"
7 8
	"testing"

9
	"github.com/ethereum/go-ethereum/common"
10
	"github.com/ethereum/go-ethereum/common/hexutil"
11 12
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/rlp"
13
	"github.com/stretchr/testify/require"
14 15 16 17

	"github.com/ethereum-optimism/optimism/op-node/rollup"
	"github.com/ethereum-optimism/optimism/op-service/eth"
	"github.com/ethereum-optimism/optimism/op-service/testutils"
18 19
)

20
func RandomRawSpanBatch(rng *rand.Rand, chainId *big.Int) *RawSpanBatch {
21
	blockCount := uint64(4 + rng.Int()&0xFF) // at least 4
22 23 24 25 26 27 28 29 30 31
	originBits := new(big.Int)
	for i := 0; i < int(blockCount); i++ {
		bit := uint(0)
		if testutils.RandomBool(rng) {
			bit = uint(1)
		}
		originBits.SetBit(originBits, i, bit)
	}
	var blockTxCounts []uint64
	totalblockTxCounts := uint64(0)
32 33
	for i := 0; i < int(blockCount); i++ {
		blockTxCount := 1 + uint64(rng.Intn(16))
34 35 36
		blockTxCounts = append(blockTxCounts, blockTxCount)
		totalblockTxCounts += blockTxCount
	}
37
	londonSigner := types.NewLondonSigner(chainId)
38 39
	var txs [][]byte
	for i := 0; i < int(totalblockTxCounts); i++ {
40
		var tx *types.Transaction
41 42 43 44 45 46 47 48 49
		switch i % 4 {
		case 0:
			tx = testutils.RandomLegacyTx(rng, types.HomesteadSigner{})
		case 1:
			tx = testutils.RandomLegacyTx(rng, londonSigner)
		case 2:
			tx = testutils.RandomAccessListTx(rng, londonSigner)
		case 3:
			tx = testutils.RandomDynamicFeeTx(rng, londonSigner)
50
		}
51 52 53 54 55 56 57 58 59 60 61 62 63 64
		rawTx, err := tx.MarshalBinary()
		if err != nil {
			panic("MarshalBinary:" + err.Error())
		}
		txs = append(txs, rawTx)
	}
	spanBatchTxs, err := newSpanBatchTxs(txs, chainId)
	if err != nil {
		panic(err.Error())
	}
	rawSpanBatch := RawSpanBatch{
		spanBatchPrefix: spanBatchPrefix{
			relTimestamp:  uint64(rng.Uint32()),
			l1OriginNum:   rng.Uint64(),
65 66
			parentCheck:   [20]byte(testutils.RandomData(rng, 20)),
			l1OriginCheck: [20]byte(testutils.RandomData(rng, 20)),
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
		},
		spanBatchPayload: spanBatchPayload{
			blockCount:    blockCount,
			originBits:    originBits,
			blockTxCounts: blockTxCounts,
			txs:           spanBatchTxs,
		},
	}
	return &rawSpanBatch
}

func RandomValidConsecutiveSingularBatches(rng *rand.Rand, chainID *big.Int) []*SingularBatch {
	blockCount := 2 + rng.Intn(128)
	l2BlockTime := uint64(2)

	var singularBatches []*SingularBatch
	for i := 0; i < blockCount; i++ {
		singularBatch := RandomSingularBatch(rng, 1+rng.Intn(8), chainID)
		singularBatches = append(singularBatches, singularBatch)
	}
	l1BlockNum := rng.Uint64()
	// make sure oldest timestamp is large enough
	singularBatches[0].Timestamp += 256
	for i := 0; i < blockCount; i++ {
		originChangedBit := rng.Intn(2)
		if originChangedBit == 1 {
			l1BlockNum++
			singularBatches[i].EpochHash = testutils.RandomHash(rng)
		} else if i > 0 {
			singularBatches[i].EpochHash = singularBatches[i-1].EpochHash
		}
		singularBatches[i].EpochNum = rollup.Epoch(l1BlockNum)
		if i > 0 {
			singularBatches[i].Timestamp = singularBatches[i-1].Timestamp + l2BlockTime
		}
	}
	return singularBatches
}

func mockL1Origin(rng *rand.Rand, rawSpanBatch *RawSpanBatch, singularBatches []*SingularBatch) []eth.L1BlockRef {
	safeHeadOrigin := testutils.RandomBlockRef(rng)
	safeHeadOrigin.Hash = singularBatches[0].EpochHash
	safeHeadOrigin.Number = uint64(singularBatches[0].EpochNum)

	l1Origins := []eth.L1BlockRef{safeHeadOrigin}
	originBitSum := uint64(0)
	for i := 0; i < int(rawSpanBatch.blockCount); i++ {
		if rawSpanBatch.originBits.Bit(i) == 1 {
			l1Origin := testutils.NextRandomRef(rng, l1Origins[originBitSum])
			originBitSum++
			l1Origin.Hash = singularBatches[i].EpochHash
			l1Origin.Number = uint64(singularBatches[i].EpochNum)
			l1Origins = append(l1Origins, l1Origin)
		}
	}
	return l1Origins
}

125
func TestBatchRoundTrip(t *testing.T) {
126 127 128 129 130
	rng := rand.New(rand.NewSource(0xdeadbeef))
	blockTime := uint64(2)
	genesisTimestamp := uint64(0)
	chainID := new(big.Int).SetUint64(rng.Uint64())

131
	batches := []*BatchData{
132 133
		NewBatchData(
			&SingularBatch{
134
				ParentHash:   common.Hash{},
protolambda's avatar
protolambda committed
135
				EpochNum:     0,
136 137 138
				Timestamp:    0,
				Transactions: []hexutil.Bytes{},
			},
139 140 141
		),
		NewBatchData(
			&SingularBatch{
142
				ParentHash:   common.Hash{31: 0x42},
protolambda's avatar
protolambda committed
143
				EpochNum:     1,
144 145 146
				Timestamp:    1647026951,
				Transactions: []hexutil.Bytes{[]byte{0, 0, 0}, []byte{0x76, 0xfd, 0x7c}},
			},
147 148 149 150 151 152
		),
		NewBatchData(RandomSingularBatch(rng, 5, chainID)),
		NewBatchData(RandomSingularBatch(rng, 7, chainID)),
		NewBatchData(RandomRawSpanBatch(rng, chainID)),
		NewBatchData(RandomRawSpanBatch(rng, chainID)),
		NewBatchData(RandomRawSpanBatch(rng, chainID)),
153 154 155 156
	}

	for i, batch := range batches {
		enc, err := batch.MarshalBinary()
157
		require.NoError(t, err)
158 159
		var dec BatchData
		err = dec.UnmarshalBinary(enc)
160 161
		require.NoError(t, err)
		if dec.GetBatchType() == SpanBatchType {
162
			_, err := DeriveSpanBatch(&dec, blockTime, genesisTimestamp, chainID)
163
			require.NoError(t, err)
164
		}
165
		require.Equal(t, batch, &dec, "Batch not equal test case %v", i)
166 167 168 169 170 171 172 173 174 175
	}
}

func TestBatchRoundTripRLP(t *testing.T) {
	rng := rand.New(rand.NewSource(0xbeefdead))
	blockTime := uint64(2)
	genesisTimestamp := uint64(0)
	chainID := new(big.Int).SetUint64(rng.Uint64())

	batches := []*BatchData{
176 177
		NewBatchData(
			&SingularBatch{
178 179 180 181 182
				ParentHash:   common.Hash{},
				EpochNum:     0,
				Timestamp:    0,
				Transactions: []hexutil.Bytes{},
			},
183 184 185
		),
		NewBatchData(
			&SingularBatch{
186 187 188 189 190
				ParentHash:   common.Hash{31: 0x42},
				EpochNum:     1,
				Timestamp:    1647026951,
				Transactions: []hexutil.Bytes{[]byte{0, 0, 0}, []byte{0x76, 0xfd, 0x7c}},
			},
191 192 193 194 195 196
		),
		NewBatchData(RandomSingularBatch(rng, 5, chainID)),
		NewBatchData(RandomSingularBatch(rng, 7, chainID)),
		NewBatchData(RandomRawSpanBatch(rng, chainID)),
		NewBatchData(RandomRawSpanBatch(rng, chainID)),
		NewBatchData(RandomRawSpanBatch(rng, chainID)),
197 198 199 200 201
	}

	for i, batch := range batches {
		var buf bytes.Buffer
		err := batch.EncodeRLP(&buf)
202
		require.NoError(t, err)
203 204 205 206 207
		result := buf.Bytes()
		var dec BatchData
		r := bytes.NewReader(result)
		s := rlp.NewStream(r, 0)
		err = dec.DecodeRLP(s)
208 209
		require.NoError(t, err)
		if dec.GetBatchType() == SpanBatchType {
210
			_, err = DeriveSpanBatch(&dec, blockTime, genesisTimestamp, chainID)
211
			require.NoError(t, err)
212
		}
213
		require.Equal(t, batch, &dec, "Batch not equal test case %v", i)
214 215
	}
}