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 }