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

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

9
	"github.com/stretchr/testify/require"
10

11
	"github.com/ethereum/go-ethereum/common"
12
	"github.com/ethereum/go-ethereum/common/hexutil"
13 14
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/rlp"
15 16 17 18

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

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
func RandomRawSpanBatch(rng *rand.Rand, chainId *big.Int) *RawSpanBatch {
	blockCount := uint64(1 + rng.Int()&0xFF)
	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)
	for i := 0; i < int(blockCount); i++ {
		blockTxCount := uint64(rng.Intn(16))
		blockTxCounts = append(blockTxCounts, blockTxCount)
		totalblockTxCounts += blockTxCount
	}
	signer := types.NewLondonSigner(chainId)
	var txs [][]byte
	for i := 0; i < int(totalblockTxCounts); i++ {
		tx := testutils.RandomTx(rng, new(big.Int).SetUint64(rng.Uint64()), signer)
		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(),
56 57
			parentCheck:   [20]byte(testutils.RandomData(rng, 20)),
			l1OriginCheck: [20]byte(testutils.RandomData(rng, 20)),
58 59 60 61 62 63 64 65 66 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 125 126 127 128 129 130 131 132 133 134 135 136 137
		},
		spanBatchPayload: spanBatchPayload{
			blockCount:    blockCount,
			originBits:    originBits,
			blockTxCounts: blockTxCounts,
			txs:           spanBatchTxs,
		},
	}
	return &rawSpanBatch
}

func RandomSingularBatch(rng *rand.Rand, txCount int, chainID *big.Int) *SingularBatch {
	signer := types.NewLondonSigner(chainID)
	baseFee := big.NewInt(rng.Int63n(300_000_000_000))
	txsEncoded := make([]hexutil.Bytes, 0, txCount)
	// force each tx to have equal chainID
	for i := 0; i < txCount; i++ {
		tx := testutils.RandomTx(rng, baseFee, signer)
		txEncoded, err := tx.MarshalBinary()
		if err != nil {
			panic("tx Marshal binary" + err.Error())
		}
		txsEncoded = append(txsEncoded, hexutil.Bytes(txEncoded))
	}
	return &SingularBatch{
		ParentHash:   testutils.RandomHash(rng),
		EpochNum:     rollup.Epoch(1 + rng.Int63n(100_000_000)),
		EpochHash:    testutils.RandomHash(rng),
		Timestamp:    uint64(rng.Int63n(2_000_000_000)),
		Transactions: txsEncoded,
	}
}

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
}

138
func TestBatchRoundTrip(t *testing.T) {
139 140 141 142 143
	rng := rand.New(rand.NewSource(0xdeadbeef))
	blockTime := uint64(2)
	genesisTimestamp := uint64(0)
	chainID := new(big.Int).SetUint64(rng.Uint64())

144
	batches := []*BatchData{
145 146
		NewBatchData(
			&SingularBatch{
147
				ParentHash:   common.Hash{},
protolambda's avatar
protolambda committed
148
				EpochNum:     0,
149 150 151
				Timestamp:    0,
				Transactions: []hexutil.Bytes{},
			},
152 153 154
		),
		NewBatchData(
			&SingularBatch{
155
				ParentHash:   common.Hash{31: 0x42},
protolambda's avatar
protolambda committed
156
				EpochNum:     1,
157 158 159
				Timestamp:    1647026951,
				Transactions: []hexutil.Bytes{[]byte{0, 0, 0}, []byte{0x76, 0xfd, 0x7c}},
			},
160 161 162 163 164 165
		),
		NewBatchData(RandomSingularBatch(rng, 5, chainID)),
		NewBatchData(RandomSingularBatch(rng, 7, chainID)),
		NewBatchData(RandomRawSpanBatch(rng, chainID)),
		NewBatchData(RandomRawSpanBatch(rng, chainID)),
		NewBatchData(RandomRawSpanBatch(rng, chainID)),
166 167 168 169
	}

	for i, batch := range batches {
		enc, err := batch.MarshalBinary()
170
		require.NoError(t, err)
171 172
		var dec BatchData
		err = dec.UnmarshalBinary(enc)
173 174 175 176 177 178
		require.NoError(t, err)
		if dec.GetBatchType() == SpanBatchType {
			rawSpanBatch, ok := dec.inner.(*RawSpanBatch)
			require.True(t, ok)
			_, err := rawSpanBatch.derive(blockTime, genesisTimestamp, chainID)
			require.NoError(t, err)
179
		}
180
		require.Equal(t, batch, &dec, "Batch not equal test case %v", i)
181 182 183 184 185 186 187 188 189 190
	}
}

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{
191 192
		NewBatchData(
			&SingularBatch{
193 194 195 196 197
				ParentHash:   common.Hash{},
				EpochNum:     0,
				Timestamp:    0,
				Transactions: []hexutil.Bytes{},
			},
198 199 200
		),
		NewBatchData(
			&SingularBatch{
201 202 203 204 205
				ParentHash:   common.Hash{31: 0x42},
				EpochNum:     1,
				Timestamp:    1647026951,
				Transactions: []hexutil.Bytes{[]byte{0, 0, 0}, []byte{0x76, 0xfd, 0x7c}},
			},
206 207 208 209 210 211
		),
		NewBatchData(RandomSingularBatch(rng, 5, chainID)),
		NewBatchData(RandomSingularBatch(rng, 7, chainID)),
		NewBatchData(RandomRawSpanBatch(rng, chainID)),
		NewBatchData(RandomRawSpanBatch(rng, chainID)),
		NewBatchData(RandomRawSpanBatch(rng, chainID)),
212 213 214 215 216
	}

	for i, batch := range batches {
		var buf bytes.Buffer
		err := batch.EncodeRLP(&buf)
217
		require.NoError(t, err)
218 219 220 221 222
		result := buf.Bytes()
		var dec BatchData
		r := bytes.NewReader(result)
		s := rlp.NewStream(r, 0)
		err = dec.DecodeRLP(s)
223 224 225 226 227 228
		require.NoError(t, err)
		if dec.GetBatchType() == SpanBatchType {
			rawSpanBatch, ok := dec.inner.(*RawSpanBatch)
			require.True(t, ok)
			_, err := rawSpanBatch.derive(blockTime, genesisTimestamp, chainID)
			require.NoError(t, err)
229
		}
230
		require.Equal(t, batch, &dec, "Batch not equal test case %v", i)
231 232
	}
}