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 }