|
| 1 | +package encoding |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "math/big" |
| 6 | + |
| 7 | + "github.com/scroll-tech/go-ethereum/core/types" |
| 8 | +) |
| 9 | + |
| 10 | +// constructSkippedBitmap constructs skipped L1 message bitmap of the batch. |
| 11 | +func constructSkippedBitmap(batchIndex uint64, chunks []*Chunk, totalL1MessagePoppedBefore uint64) ([]byte, uint64, error) { |
| 12 | + // skipped L1 message bitmap, an array of 256-bit bitmaps |
| 13 | + var skippedBitmap []*big.Int |
| 14 | + |
| 15 | + // the first queue index that belongs to this batch |
| 16 | + baseIndex := totalL1MessagePoppedBefore |
| 17 | + |
| 18 | + // the next queue index that we need to process |
| 19 | + nextIndex := totalL1MessagePoppedBefore |
| 20 | + |
| 21 | + for chunkID, chunk := range chunks { |
| 22 | + for blockID, block := range chunk.Blocks { |
| 23 | + for _, tx := range block.Transactions { |
| 24 | + if tx.Type != types.L1MessageTxType { |
| 25 | + continue |
| 26 | + } |
| 27 | + |
| 28 | + currentIndex := tx.Nonce |
| 29 | + |
| 30 | + if currentIndex < nextIndex { |
| 31 | + return nil, 0, fmt.Errorf("unexpected batch payload, expected queue index: %d, got: %d. Batch index: %d, chunk index in batch: %d, block index in chunk: %d, block hash: %v, transaction hash: %v", nextIndex, currentIndex, batchIndex, chunkID, blockID, block.Header.Hash(), tx.TxHash) |
| 32 | + } |
| 33 | + |
| 34 | + // mark skipped messages |
| 35 | + for skippedIndex := nextIndex; skippedIndex < currentIndex; skippedIndex++ { |
| 36 | + quo := int((skippedIndex - baseIndex) / 256) |
| 37 | + rem := int((skippedIndex - baseIndex) % 256) |
| 38 | + for len(skippedBitmap) <= quo { |
| 39 | + bitmap := big.NewInt(0) |
| 40 | + skippedBitmap = append(skippedBitmap, bitmap) |
| 41 | + } |
| 42 | + skippedBitmap[quo].SetBit(skippedBitmap[quo], rem, 1) |
| 43 | + } |
| 44 | + |
| 45 | + // process included message |
| 46 | + quo := int((currentIndex - baseIndex) / 256) |
| 47 | + for len(skippedBitmap) <= quo { |
| 48 | + bitmap := big.NewInt(0) |
| 49 | + skippedBitmap = append(skippedBitmap, bitmap) |
| 50 | + } |
| 51 | + |
| 52 | + nextIndex = currentIndex + 1 |
| 53 | + } |
| 54 | + } |
| 55 | + } |
| 56 | + |
| 57 | + skippedL1MessageBitmap := make([]byte, len(skippedBitmap)*skippedL1MessageBitmapByteSize) |
| 58 | + for ii, num := range skippedBitmap { |
| 59 | + bytes := num.Bytes() |
| 60 | + padding := skippedL1MessageBitmapByteSize - len(bytes) |
| 61 | + copy(skippedL1MessageBitmap[skippedL1MessageBitmapByteSize*ii+padding:], bytes) |
| 62 | + } |
| 63 | + |
| 64 | + return skippedL1MessageBitmap, nextIndex, nil |
| 65 | +} |
| 66 | + |
| 67 | +// DecodeBitmap decodes skipped L1 message bitmap of the batch from bytes to big.Int's. |
| 68 | +func DecodeBitmap(skippedL1MessageBitmap []byte, totalL1MessagePopped int) ([]*big.Int, error) { |
| 69 | + length := len(skippedL1MessageBitmap) |
| 70 | + if length%skippedL1MessageBitmapByteSize != 0 { |
| 71 | + return nil, fmt.Errorf("skippedL1MessageBitmap length doesn't match, skippedL1MessageBitmap length should be equal 0 modulo %v, length of skippedL1MessageBitmap: %v", skippedL1MessageBitmapByteSize, length) |
| 72 | + } |
| 73 | + if length*8 < totalL1MessagePopped { |
| 74 | + return nil, fmt.Errorf("skippedL1MessageBitmap length is too small, skippedL1MessageBitmap length should be at least %v, length of skippedL1MessageBitmap: %v", (totalL1MessagePopped+7)/8, length) |
| 75 | + } |
| 76 | + var skippedBitmap []*big.Int |
| 77 | + for index := 0; index < length/skippedL1MessageBitmapByteSize; index++ { |
| 78 | + bitmap := big.NewInt(0).SetBytes(skippedL1MessageBitmap[index*skippedL1MessageBitmapByteSize : index*skippedL1MessageBitmapByteSize+skippedL1MessageBitmapByteSize]) |
| 79 | + skippedBitmap = append(skippedBitmap, bitmap) |
| 80 | + } |
| 81 | + return skippedBitmap, nil |
| 82 | +} |
| 83 | + |
| 84 | +// IsL1MessageSkipped checks if the L1 message at the given index is skipped. |
| 85 | +func IsL1MessageSkipped(skippedBitmap []*big.Int, index uint64) bool { |
| 86 | + if index >= uint64(len(skippedBitmap))*256 { |
| 87 | + return false |
| 88 | + } |
| 89 | + quo := index / 256 |
| 90 | + rem := index % 256 |
| 91 | + return skippedBitmap[quo].Bit(int(rem)) == 1 |
| 92 | +} |
0 commit comments