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 }