github.com/ethereum-optimism/optimism/l2geth@v0.0.0-20230612200230-50b04ade19e3/common/varbytes.go (about)

     1  // Copyright (c) 2013-2016 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package common
     6  
     7  import (
     8  	"encoding/binary"
     9  	"fmt"
    10  	"io"
    11  	"math"
    12  )
    13  
    14  const (
    15  	// MaxVarIntPayload is the maximum payload size for a variable length integer.
    16  	MaxVarIntPayload = 9
    17  
    18  	// binaryFreeListMaxItems is the number of buffers to keep in the free
    19  	// list to use for binary serialization and deserialization.
    20  	binaryFreeListMaxItems = 1024
    21  )
    22  
    23  var (
    24  	// littleEndian is a convenience variable since binary.LittleEndian is
    25  	// quite long.
    26  	littleEndian = binary.LittleEndian
    27  )
    28  
    29  // binaryFreeList defines a concurrent safe free list of byte slices (up to the
    30  // maximum number defined by the binaryFreeListMaxItems constant) that have a
    31  // cap of 8 (thus it supports up to a uint64).  It is used to provide temporary
    32  // buffers for serializing and deserializing primitive numbers to and from their
    33  // binary encoding in order to greatly reduce the number of allocations
    34  // required.
    35  //
    36  // For convenience, functions are provided for each of the primitive unsigned
    37  // integers that automatically obtain a buffer from the free list, perform the
    38  // necessary binary conversion, read from or write to the given io.Reader or
    39  // io.Writer, and return the buffer to the free list.
    40  type binaryFreeList chan []byte
    41  
    42  // Borrow returns a byte slice from the free list with a length of 8.  A new
    43  // buffer is allocated if there are not any available on the free list.
    44  func (l binaryFreeList) Borrow() []byte {
    45  	var buf []byte
    46  	select {
    47  	case buf = <-l:
    48  	default:
    49  		buf = make([]byte, 8)
    50  	}
    51  	return buf[:8]
    52  }
    53  
    54  // Return puts the provided byte slice back on the free list.  The buffer MUST
    55  // have been obtained via the Borrow function and therefore have a cap of 8.
    56  func (l binaryFreeList) Return(buf []byte) {
    57  	select {
    58  	case l <- buf:
    59  	default:
    60  		// Let it go to the garbage collector.
    61  	}
    62  }
    63  
    64  // Uint8 reads a single byte from the provided reader using a buffer from the
    65  // free list and returns it as a uint8.
    66  func (l binaryFreeList) Uint8(r io.Reader) (uint8, error) {
    67  	buf := l.Borrow()[:1]
    68  	if _, err := io.ReadFull(r, buf); err != nil {
    69  		l.Return(buf)
    70  		return 0, err
    71  	}
    72  	rv := buf[0]
    73  	l.Return(buf)
    74  	return rv, nil
    75  }
    76  
    77  // Uint16 reads two bytes from the provided reader using a buffer from the
    78  // free list, converts it to a number using the provided byte order, and returns
    79  // the resulting uint16.
    80  func (l binaryFreeList) Uint16(r io.Reader, byteOrder binary.ByteOrder) (uint16, error) {
    81  	buf := l.Borrow()[:2]
    82  	if _, err := io.ReadFull(r, buf); err != nil {
    83  		l.Return(buf)
    84  		return 0, err
    85  	}
    86  	rv := byteOrder.Uint16(buf)
    87  	l.Return(buf)
    88  	return rv, nil
    89  }
    90  
    91  // Uint32 reads four bytes from the provided reader using a buffer from the
    92  // free list, converts it to a number using the provided byte order, and returns
    93  // the resulting uint32.
    94  func (l binaryFreeList) Uint32(r io.Reader, byteOrder binary.ByteOrder) (uint32, error) {
    95  	buf := l.Borrow()[:4]
    96  	if _, err := io.ReadFull(r, buf); err != nil {
    97  		l.Return(buf)
    98  		return 0, err
    99  	}
   100  	rv := byteOrder.Uint32(buf)
   101  	l.Return(buf)
   102  	return rv, nil
   103  }
   104  
   105  // Uint64 reads eight bytes from the provided reader using a buffer from the
   106  // free list, converts it to a number using the provided byte order, and returns
   107  // the resulting uint64.
   108  func (l binaryFreeList) Uint64(r io.Reader, byteOrder binary.ByteOrder) (uint64, error) {
   109  	buf := l.Borrow()[:8]
   110  	if _, err := io.ReadFull(r, buf); err != nil {
   111  		l.Return(buf)
   112  		return 0, err
   113  	}
   114  	rv := byteOrder.Uint64(buf)
   115  	l.Return(buf)
   116  	return rv, nil
   117  }
   118  
   119  // PutUint8 copies the provided uint8 into a buffer from the free list and
   120  // writes the resulting byte to the given writer.
   121  func (l binaryFreeList) PutUint8(w io.Writer, val uint8) error {
   122  	buf := l.Borrow()[:1]
   123  	buf[0] = val
   124  	_, err := w.Write(buf)
   125  	l.Return(buf)
   126  	return err
   127  }
   128  
   129  // PutUint16 serializes the provided uint16 using the given byte order into a
   130  // buffer from the free list and writes the resulting two bytes to the given
   131  // writer.
   132  func (l binaryFreeList) PutUint16(w io.Writer, byteOrder binary.ByteOrder, val uint16) error {
   133  	buf := l.Borrow()[:2]
   134  	byteOrder.PutUint16(buf, val)
   135  	_, err := w.Write(buf)
   136  	l.Return(buf)
   137  	return err
   138  }
   139  
   140  // PutUint32 serializes the provided uint32 using the given byte order into a
   141  // buffer from the free list and writes the resulting four bytes to the given
   142  // writer.
   143  func (l binaryFreeList) PutUint32(w io.Writer, byteOrder binary.ByteOrder, val uint32) error {
   144  	buf := l.Borrow()[:4]
   145  	byteOrder.PutUint32(buf, val)
   146  	_, err := w.Write(buf)
   147  	l.Return(buf)
   148  	return err
   149  }
   150  
   151  // PutUint64 serializes the provided uint64 using the given byte order into a
   152  // buffer from the free list and writes the resulting eight bytes to the given
   153  // writer.
   154  func (l binaryFreeList) PutUint64(w io.Writer, byteOrder binary.ByteOrder, val uint64) error {
   155  	buf := l.Borrow()[:8]
   156  	byteOrder.PutUint64(buf, val)
   157  	_, err := w.Write(buf)
   158  	l.Return(buf)
   159  	return err
   160  }
   161  
   162  // binarySerializer provides a free list of buffers to use for serializing and
   163  // deserializing primitive integer values to and from io.Readers and io.Writers.
   164  var binarySerializer binaryFreeList = make(chan []byte, binaryFreeListMaxItems)
   165  
   166  // errNonCanonicalVarInt is the common format string used for non-canonically
   167  // encoded variable length integer errors.
   168  var errNonCanonicalVarInt = "non-canonical varint %x - discriminant %x must " +
   169  	"encode a value greater than %x"
   170  
   171  // ReadVarInt reads a variable length integer from r and returns it as a uint64.
   172  func ReadVarInt(r io.Reader, pver uint32) (uint64, error) {
   173  	discriminant, err := binarySerializer.Uint8(r)
   174  	if err != nil {
   175  		return 0, err
   176  	}
   177  
   178  	var rv uint64
   179  	switch discriminant {
   180  	case 0xff:
   181  		sv, err := binarySerializer.Uint64(r, littleEndian)
   182  		if err != nil {
   183  			return 0, err
   184  		}
   185  		rv = sv
   186  
   187  		// The encoding is not canonical if the value could have been
   188  		// encoded using fewer bytes.
   189  		min := uint64(0x100000000)
   190  		if rv < min {
   191  			return 0, messageError("ReadVarInt", fmt.Sprintf(
   192  				errNonCanonicalVarInt, rv, discriminant, min))
   193  		}
   194  
   195  	case 0xfe:
   196  		sv, err := binarySerializer.Uint32(r, littleEndian)
   197  		if err != nil {
   198  			return 0, err
   199  		}
   200  		rv = uint64(sv)
   201  
   202  		// The encoding is not canonical if the value could have been
   203  		// encoded using fewer bytes.
   204  		min := uint64(0x10000)
   205  		if rv < min {
   206  			return 0, messageError("ReadVarInt", fmt.Sprintf(
   207  				errNonCanonicalVarInt, rv, discriminant, min))
   208  		}
   209  
   210  	case 0xfd:
   211  		sv, err := binarySerializer.Uint16(r, littleEndian)
   212  		if err != nil {
   213  			return 0, err
   214  		}
   215  		rv = uint64(sv)
   216  
   217  		// The encoding is not canonical if the value could have been
   218  		// encoded using fewer bytes.
   219  		min := uint64(0xfd)
   220  		if rv < min {
   221  			return 0, messageError("ReadVarInt", fmt.Sprintf(
   222  				errNonCanonicalVarInt, rv, discriminant, min))
   223  		}
   224  
   225  	default:
   226  		rv = uint64(discriminant)
   227  	}
   228  
   229  	return rv, nil
   230  }
   231  
   232  // WriteVarInt serializes val to w using a variable number of bytes depending
   233  // on its value.
   234  func WriteVarInt(w io.Writer, pver uint32, val uint64) error {
   235  	if val < 0xfd {
   236  		return binarySerializer.PutUint8(w, uint8(val))
   237  	}
   238  
   239  	if val <= math.MaxUint16 {
   240  		err := binarySerializer.PutUint8(w, 0xfd)
   241  		if err != nil {
   242  			return err
   243  		}
   244  		return binarySerializer.PutUint16(w, littleEndian, uint16(val))
   245  	}
   246  
   247  	if val <= math.MaxUint32 {
   248  		err := binarySerializer.PutUint8(w, 0xfe)
   249  		if err != nil {
   250  			return err
   251  		}
   252  		return binarySerializer.PutUint32(w, littleEndian, uint32(val))
   253  	}
   254  
   255  	err := binarySerializer.PutUint8(w, 0xff)
   256  	if err != nil {
   257  		return err
   258  	}
   259  	return binarySerializer.PutUint64(w, littleEndian, val)
   260  }
   261  
   262  // VarIntSerializeSize returns the number of bytes it would take to serialize
   263  // val as a variable length integer.
   264  func VarIntSerializeSize(val uint64) int {
   265  	// The value is small enough to be represented by itself, so it's
   266  	// just 1 byte.
   267  	if val < 0xfd {
   268  		return 1
   269  	}
   270  
   271  	// Discriminant 1 byte plus 2 bytes for the uint16.
   272  	if val <= math.MaxUint16 {
   273  		return 3
   274  	}
   275  
   276  	// Discriminant 1 byte plus 4 bytes for the uint32.
   277  	if val <= math.MaxUint32 {
   278  		return 5
   279  	}
   280  
   281  	// Discriminant 1 byte plus 8 bytes for the uint64.
   282  	return 9
   283  }
   284  
   285  // ReadVarString reads a variable length string from r and returns it as a Go
   286  // string.  A variable length string is encoded as a variable length integer
   287  // containing the length of the string followed by the bytes that represent the
   288  // string itself.
   289  func ReadVarString(r io.Reader, pver uint32) (string, error) {
   290  	count, err := ReadVarInt(r, pver)
   291  	if err != nil {
   292  		return "", err
   293  	}
   294  
   295  	buf := make([]byte, count)
   296  	_, err = io.ReadFull(r, buf)
   297  	if err != nil {
   298  		return "", err
   299  	}
   300  	return string(buf), nil
   301  }
   302  
   303  // WriteVarString serializes str to w as a variable length integer containing
   304  // the length of the string followed by the bytes that represent the string
   305  // itself.
   306  func WriteVarString(w io.Writer, pver uint32, str string) error {
   307  	err := WriteVarInt(w, pver, uint64(len(str)))
   308  	if err != nil {
   309  		return err
   310  	}
   311  	_, err = w.Write([]byte(str))
   312  	return err
   313  }
   314  
   315  // ReadVarBytes reads a variable length byte array.  A byte array is encoded
   316  // as a varInt containing the length of the array followed by the bytes
   317  // themselves.  An error is returned if the length is greater than the
   318  // passed maxAllowed parameter which helps protect against memory exhaustion
   319  // attacks and forced panics through malformed messages.  The fieldName
   320  // parameter is only used for the error message so it provides more context in
   321  // the error.
   322  func ReadVarBytes(r io.Reader, pver uint32, maxAllowed uint32,
   323  	fieldName string) ([]byte, error) {
   324  
   325  	count, err := ReadVarInt(r, pver)
   326  	if err != nil {
   327  		return nil, err
   328  	}
   329  
   330  	// Prevent byte array larger than the max message size.  It would
   331  	// be possible to cause memory exhaustion and panics without a sane
   332  	// upper bound on this count.
   333  	if count > uint64(maxAllowed) {
   334  		str := fmt.Sprintf("%s is larger than the max allowed size "+
   335  			"[count %d, max %d]", fieldName, count, maxAllowed)
   336  		return nil, messageError("ReadVarBytes", str)
   337  	}
   338  
   339  	b := make([]byte, count)
   340  	_, err = io.ReadFull(r, b)
   341  	if err != nil {
   342  		return nil, err
   343  	}
   344  	return b, nil
   345  }
   346  
   347  // WriteVarBytes serializes a variable length byte array to w as a varInt
   348  // containing the number of bytes, followed by the bytes themselves.
   349  func WriteVarBytes(w io.Writer, pver uint32, bytes []byte) error {
   350  	slen := uint64(len(bytes))
   351  	err := WriteVarInt(w, pver, slen)
   352  	if err != nil {
   353  		return err
   354  	}
   355  
   356  	_, err = w.Write(bytes)
   357  	return err
   358  }
   359  
   360  // MessageError describes an issue with a message.
   361  // An example of some potential issues are messages from the wrong bitcoin
   362  // network, invalid commands, mismatched checksums, and exceeding max payloads.
   363  //
   364  // This provides a mechanism for the caller to type assert the error to
   365  // differentiate between general io errors such as io.EOF and issues that
   366  // resulted from malformed messages.
   367  type MessageError struct {
   368  	Func        string // Function name
   369  	Description string // Human readable description of the issue
   370  }
   371  
   372  // Error satisfies the error interface and prints human-readable errors.
   373  func (e *MessageError) Error() string {
   374  	if e.Func != "" {
   375  		return fmt.Sprintf("%v: %v", e.Func, e.Description)
   376  	}
   377  	return e.Description
   378  }
   379  
   380  // messageError creates an error for the given function and description.
   381  func messageError(f string, desc string) *MessageError {
   382  	return &MessageError{Func: f, Description: desc}
   383  }