github.com/ethereum-optimism/optimism@v1.7.2/op-node/rollup/derive/span_batch_util.go (about) 1 package derive 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "math/big" 8 ) 9 10 // decodeSpanBatchBits decodes a standard span-batch bitlist. 11 // The bitlist is encoded as big-endian integer, left-padded with zeroes to a multiple of 8 bits. 12 // The encoded bitlist cannot be longer than MaxSpanBatchSize. 13 func decodeSpanBatchBits(r *bytes.Reader, bitLength uint64) (*big.Int, error) { 14 // Round up, ensure enough bytes when number of bits is not a multiple of 8. 15 // Alternative of (L+7)/8 is not overflow-safe. 16 bufLen := bitLength / 8 17 if bitLength%8 != 0 { 18 bufLen++ 19 } 20 // avoid out of memory before allocation 21 if bufLen > MaxSpanBatchSize { 22 return nil, ErrTooBigSpanBatchSize 23 } 24 buf := make([]byte, bufLen) 25 _, err := io.ReadFull(r, buf) 26 if err != nil { 27 return nil, fmt.Errorf("failed to read bits: %w", err) 28 } 29 out := new(big.Int) 30 out.SetBytes(buf) 31 // We read the correct number of bytes, but there may still be trailing bits 32 if l := uint64(out.BitLen()); l > bitLength { 33 return nil, fmt.Errorf("bitfield has %d bits, but expected no more than %d", l, bitLength) 34 } 35 return out, nil 36 } 37 38 // encodeSpanBatchBits encodes a standard span-batch bitlist. 39 // The bitlist is encoded as big-endian integer, left-padded with zeroes to a multiple of 8 bits. 40 // The encoded bitlist cannot be longer than MaxSpanBatchSize. 41 func encodeSpanBatchBits(w io.Writer, bitLength uint64, bits *big.Int) error { 42 if l := uint64(bits.BitLen()); l > bitLength { 43 return fmt.Errorf("bitfield is larger than bitLength: %d > %d", l, bitLength) 44 } 45 // Round up, ensure enough bytes when number of bits is not a multiple of 8. 46 // Alternative of (L+7)/8 is not overflow-safe. 47 bufLen := bitLength / 8 48 if bitLength%8 != 0 { // rounding up this way is safe against overflows 49 bufLen++ 50 } 51 if bufLen > MaxSpanBatchSize { 52 return ErrTooBigSpanBatchSize 53 } 54 buf := make([]byte, bufLen) 55 bits.FillBytes(buf) // zero-extended, big-endian 56 if _, err := w.Write(buf); err != nil { 57 return fmt.Errorf("cannot write bits: %w", err) 58 } 59 return nil 60 }