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  }