github.com/ledgerwatch/erigon-lib@v1.0.0/rlp/encodel.go (about)

     1  /*
     2     Copyright 2021 The Erigon contributors
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package rlp
    18  
    19  import (
    20  	"encoding/binary"
    21  	"math/bits"
    22  
    23  	"github.com/ledgerwatch/erigon-lib/common"
    24  )
    25  
    26  // General design:
    27  //      - rlp package doesn't manage memory - and Caller must ensure buffers are big enough.
    28  //      - no io.Writer, because it's incompatible with binary.BigEndian functions and Writer can't be used as temporary buffer
    29  //
    30  // Composition:
    31  //     - each Encode method does write to given buffer and return written len
    32  //     - each Parse accept position in payload and return new position
    33  //
    34  // General rules:
    35  //      - functions to calculate prefix len are fast (and pure). it's ok to call them multiple times during encoding of large object for readability.
    36  //      - rlp has 2 data types: List and String (bytes array), and low-level funcs are operate with this types.
    37  //      - but for convenience and performance - provided higher-level functions (for example for EncodeHash - for []byte of len 32)
    38  //      - functions to Parse (Decode) data - using data type as name (without any prefix): rlp.String(), rlp.List, rlp.U64(), rlp.U256()
    39  //
    40  
    41  func ListPrefixLen(dataLen int) int {
    42  	if dataLen >= 56 {
    43  		return 1 + common.BitLenToByteLen(bits.Len64(uint64(dataLen)))
    44  	}
    45  	return 1
    46  }
    47  func EncodeListPrefix(dataLen int, to []byte) int {
    48  	if dataLen >= 56 {
    49  		_ = to[9]
    50  		beLen := common.BitLenToByteLen(bits.Len64(uint64(dataLen)))
    51  		binary.BigEndian.PutUint64(to[1:], uint64(dataLen))
    52  		to[8-beLen] = 247 + byte(beLen)
    53  		copy(to, to[8-beLen:9])
    54  		return 1 + beLen
    55  	}
    56  	to[0] = 192 + byte(dataLen)
    57  	return 1
    58  }
    59  
    60  func U32Len(i uint32) int {
    61  	if i < 128 {
    62  		return 1
    63  	}
    64  	return 1 + common.BitLenToByteLen(bits.Len32(i))
    65  }
    66  
    67  func U64Len(i uint64) int {
    68  	if i < 128 {
    69  		return 1
    70  	}
    71  	return 1 + common.BitLenToByteLen(bits.Len64(i))
    72  }
    73  
    74  func EncodeU32(i uint32, to []byte) int {
    75  	if i == 0 {
    76  		to[0] = 128
    77  		return 1
    78  	}
    79  	if i < 128 {
    80  		to[0] = byte(i) // fits single byte
    81  		return 1
    82  	}
    83  
    84  	b := to[1:]
    85  	var l int
    86  
    87  	// writes i to b in big endian byte order, using the least number of bytes needed to represent i.
    88  	switch {
    89  	case i < (1 << 8):
    90  		b[0] = byte(i)
    91  		l = 1
    92  	case i < (1 << 16):
    93  		b[0] = byte(i >> 8)
    94  		b[1] = byte(i)
    95  		l = 2
    96  	case i < (1 << 24):
    97  		b[0] = byte(i >> 16)
    98  		b[1] = byte(i >> 8)
    99  		b[2] = byte(i)
   100  		l = 3
   101  	default:
   102  		b[0] = byte(i >> 24)
   103  		b[1] = byte(i >> 16)
   104  		b[2] = byte(i >> 8)
   105  		b[3] = byte(i)
   106  		l = 4
   107  	}
   108  
   109  	to[0] = 128 + byte(l)
   110  	return 1 + l
   111  }
   112  
   113  func EncodeU64(i uint64, to []byte) int {
   114  	if i == 0 {
   115  		to[0] = 128
   116  		return 1
   117  	}
   118  	if i < 128 {
   119  		to[0] = byte(i) // fits single byte
   120  		return 1
   121  	}
   122  
   123  	b := to[1:]
   124  	var l int
   125  
   126  	// writes i to b in big endian byte order, using the least number of bytes needed to represent i.
   127  	switch {
   128  	case i < (1 << 8):
   129  		b[0] = byte(i)
   130  		l = 1
   131  	case i < (1 << 16):
   132  		b[0] = byte(i >> 8)
   133  		b[1] = byte(i)
   134  		l = 2
   135  	case i < (1 << 24):
   136  		b[0] = byte(i >> 16)
   137  		b[1] = byte(i >> 8)
   138  		b[2] = byte(i)
   139  		l = 3
   140  	case i < (1 << 32):
   141  		b[0] = byte(i >> 24)
   142  		b[1] = byte(i >> 16)
   143  		b[2] = byte(i >> 8)
   144  		b[3] = byte(i)
   145  		l = 4
   146  	case i < (1 << 40):
   147  		b[0] = byte(i >> 32)
   148  		b[1] = byte(i >> 24)
   149  		b[2] = byte(i >> 16)
   150  		b[3] = byte(i >> 8)
   151  		b[4] = byte(i)
   152  		l = 5
   153  	case i < (1 << 48):
   154  		b[0] = byte(i >> 40)
   155  		b[1] = byte(i >> 32)
   156  		b[2] = byte(i >> 24)
   157  		b[3] = byte(i >> 16)
   158  		b[4] = byte(i >> 8)
   159  		b[5] = byte(i)
   160  		l = 6
   161  	case i < (1 << 56):
   162  		b[0] = byte(i >> 48)
   163  		b[1] = byte(i >> 40)
   164  		b[2] = byte(i >> 32)
   165  		b[3] = byte(i >> 24)
   166  		b[4] = byte(i >> 16)
   167  		b[5] = byte(i >> 8)
   168  		b[6] = byte(i)
   169  		l = 7
   170  	default:
   171  		b[0] = byte(i >> 56)
   172  		b[1] = byte(i >> 48)
   173  		b[2] = byte(i >> 40)
   174  		b[3] = byte(i >> 32)
   175  		b[4] = byte(i >> 24)
   176  		b[5] = byte(i >> 16)
   177  		b[6] = byte(i >> 8)
   178  		b[7] = byte(i)
   179  		l = 8
   180  	}
   181  
   182  	to[0] = 128 + byte(l)
   183  	return 1 + l
   184  }
   185  
   186  func StringLen(s []byte) int {
   187  	sLen := len(s)
   188  	switch {
   189  	case sLen > 56:
   190  		beLen := common.BitLenToByteLen(bits.Len(uint(sLen)))
   191  		return 1 + beLen + sLen
   192  	case sLen == 0:
   193  		return 1
   194  	case sLen == 1:
   195  		if s[0] < 128 {
   196  			return 1
   197  		}
   198  		return 1 + sLen
   199  	default: // 1<s<56
   200  		return 1 + sLen
   201  	}
   202  }
   203  func EncodeString(s []byte, to []byte) int {
   204  	switch {
   205  	case len(s) > 56:
   206  		beLen := common.BitLenToByteLen(bits.Len(uint(len(s))))
   207  		binary.BigEndian.PutUint64(to[1:], uint64(len(s)))
   208  		_ = to[beLen+len(s)]
   209  
   210  		to[8-beLen] = byte(beLen) + 183
   211  		copy(to, to[8-beLen:9])
   212  		copy(to[1+beLen:], s)
   213  		return 1 + beLen + len(s)
   214  	case len(s) == 0:
   215  		to[0] = 128
   216  		return 1
   217  	case len(s) == 1:
   218  		if s[0] < 128 {
   219  			to[0] = s[0]
   220  			return 1
   221  		}
   222  		to[0] = 129
   223  		to[1] = s[0]
   224  		return 2
   225  	default: // 1<s<56
   226  		_ = to[len(s)]
   227  		to[0] = byte(len(s)) + 128
   228  		copy(to[1:], s)
   229  		return 1 + len(s)
   230  	}
   231  }
   232  
   233  // EncodeHash assumes that `to` buffer is already 32bytes long
   234  func EncodeHash(h, to []byte) int {
   235  	_ = to[32] // early bounds check to guarantee safety of writes below
   236  	to[0] = 128 + 32
   237  	copy(to[1:33], h[:32])
   238  	return 33
   239  }
   240  
   241  func HashesLen(hashes []byte) int {
   242  	hashesLen := len(hashes) / 32 * 33
   243  	return ListPrefixLen(hashesLen) + hashesLen
   244  }
   245  
   246  func EncodeHashes(hashes []byte, encodeBuf []byte) int {
   247  	pos := 0
   248  	hashesLen := len(hashes) / 32 * 33
   249  	pos += EncodeListPrefix(hashesLen, encodeBuf)
   250  	for i := 0; i < len(hashes); i += 32 {
   251  		pos += EncodeHash(hashes[i:], encodeBuf[pos:])
   252  	}
   253  	return pos
   254  }
   255  
   256  func AnnouncementsLen(types []byte, sizes []uint32, hashes []byte) int {
   257  	if len(types) == 0 {
   258  		return 4
   259  	}
   260  	typesLen := StringLen(types)
   261  	var sizesLen int
   262  	for _, size := range sizes {
   263  		sizesLen += U32Len(size)
   264  	}
   265  	hashesLen := len(hashes) / 32 * 33
   266  	totalLen := typesLen + sizesLen + ListPrefixLen(sizesLen) + hashesLen + ListPrefixLen(hashesLen)
   267  	return ListPrefixLen(totalLen) + totalLen
   268  }
   269  
   270  // EIP-5793: eth/68 - Add tx type to tx announcement
   271  func EncodeAnnouncements(types []byte, sizes []uint32, hashes []byte, encodeBuf []byte) int {
   272  	if len(types) == 0 {
   273  		encodeBuf[0] = 0xc3
   274  		encodeBuf[1] = 0x80
   275  		encodeBuf[2] = 0xc0
   276  		encodeBuf[3] = 0xc0
   277  		return 4
   278  	}
   279  	pos := 0
   280  	typesLen := StringLen(types)
   281  	var sizesLen int
   282  	for _, size := range sizes {
   283  		sizesLen += U32Len(size)
   284  	}
   285  	hashesLen := len(hashes) / 32 * 33
   286  	totalLen := typesLen + sizesLen + ListPrefixLen(sizesLen) + hashesLen + ListPrefixLen(hashesLen)
   287  	pos += EncodeListPrefix(totalLen, encodeBuf)
   288  	pos += EncodeString(types, encodeBuf[pos:])
   289  	pos += EncodeListPrefix(sizesLen, encodeBuf[pos:])
   290  	for _, size := range sizes {
   291  		pos += EncodeU32(size, encodeBuf[pos:])
   292  	}
   293  	pos += EncodeListPrefix(hashesLen, encodeBuf[pos:])
   294  	for i := 0; i < len(hashes); i += 32 {
   295  		pos += EncodeHash(hashes[i:], encodeBuf[pos:])
   296  	}
   297  	return pos
   298  }