github.com/ledgerwatch/erigon-lib@v1.0.0/rlp/parse.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 "errors" 21 "fmt" 22 23 "github.com/holiman/uint256" 24 25 "github.com/ledgerwatch/erigon-lib/common" 26 ) 27 28 var ( 29 ErrBase = fmt.Errorf("rlp") 30 ErrParse = fmt.Errorf("%w parse", ErrBase) 31 ErrDecode = fmt.Errorf("%w decode", ErrBase) 32 ) 33 34 func IsRLPError(err error) bool { return errors.Is(err, ErrBase) } 35 36 // BeInt parses Big Endian representation of an integer from given payload at given position 37 func BeInt(payload []byte, pos, length int) (int, error) { 38 var r int 39 if pos+length >= len(payload) { 40 return 0, fmt.Errorf("%w: unexpected end of payload", ErrParse) 41 } 42 if length > 0 && payload[pos] == 0 { 43 return 0, fmt.Errorf("%w: integer encoding for RLP must not have leading zeros: %x", ErrParse, payload[pos:pos+length]) 44 } 45 for _, b := range payload[pos : pos+length] { 46 r = (r << 8) | int(b) 47 } 48 return r, nil 49 } 50 51 // Prefix parses RLP Prefix from given payload at given position. It returns the offset and length of the RLP element 52 // as well as the indication of whether it is a list of string 53 func Prefix(payload []byte, pos int) (dataPos int, dataLen int, isList bool, err error) { 54 if pos < 0 { 55 return 0, 0, false, fmt.Errorf("%w: negative position not allowed", ErrParse) 56 } 57 if pos >= len(payload) { 58 return 0, 0, false, fmt.Errorf("%w: unexpected end of payload", ErrParse) 59 } 60 switch first := payload[pos]; { 61 case first < 128: 62 dataPos = pos 63 dataLen = 1 64 isList = false 65 case first < 184: 66 // Otherwise, if a string is 0-55 bytes long, 67 // the RLP encoding consists of a single byte with value 0x80 plus the 68 // length of the string followed by the string. The range of the first 69 // byte is thus [0x80, 0xB7]. 70 dataPos = pos + 1 71 dataLen = int(first) - 128 72 isList = false 73 if dataLen == 1 && dataPos < len(payload) && payload[dataPos] < 128 { 74 err = fmt.Errorf("%w: non-canonical size information", ErrParse) 75 } 76 case first < 192: 77 // If a string is more than 55 bytes long, the 78 // RLP encoding consists of a single byte with value 0xB7 plus the length 79 // of the length of the string in binary form, followed by the length of 80 // the string, followed by the string. For example, a length-1024 string 81 // would be encoded as 0xB90400 followed by the string. The range of 82 // the first byte is thus [0xB8, 0xBF]. 83 beLen := int(first) - 183 84 dataPos = pos + 1 + beLen 85 dataLen, err = BeInt(payload, pos+1, beLen) 86 isList = false 87 if dataLen < 56 { 88 err = fmt.Errorf("%w: non-canonical size information", ErrParse) 89 } 90 case first < 248: 91 // isList of len < 56 92 // If the total payload of a list 93 // (i.e. the combined length of all its items) is 0-55 bytes long, the 94 // RLP encoding consists of a single byte with value 0xC0 plus the length 95 // of the list followed by the concatenation of the RLP encodings of the 96 // items. The range of the first byte is thus [0xC0, 0xF7]. 97 dataPos = pos + 1 98 dataLen = int(first) - 192 99 isList = true 100 default: 101 // If the total payload of a list is more than 55 bytes long, 102 // the RLP encoding consists of a single byte with value 0xF7 103 // plus the length of the length of the payload in binary 104 // form, followed by the length of the payload, followed by 105 // the concatenation of the RLP encodings of the items. The 106 // range of the first byte is thus [0xF8, 0xFF]. 107 beLen := int(first) - 247 108 dataPos = pos + 1 + beLen 109 dataLen, err = BeInt(payload, pos+1, beLen) 110 isList = true 111 if dataLen < 56 { 112 err = fmt.Errorf("%w: : non-canonical size information", ErrParse) 113 } 114 } 115 if err == nil { 116 if dataPos+dataLen > len(payload) { 117 err = fmt.Errorf("%w: unexpected end of payload", ErrParse) 118 } else if dataPos+dataLen < 0 { 119 err = fmt.Errorf("%w: found too big len", ErrParse) 120 } 121 } 122 return 123 } 124 125 func List(payload []byte, pos int) (dataPos, dataLen int, err error) { 126 dataPos, dataLen, isList, err := Prefix(payload, pos) 127 if err != nil { 128 return 0, 0, err 129 } 130 if !isList { 131 return 0, 0, fmt.Errorf("%w: must be a list", ErrParse) 132 } 133 return 134 } 135 136 func String(payload []byte, pos int) (dataPos, dataLen int, err error) { 137 dataPos, dataLen, isList, err := Prefix(payload, pos) 138 if err != nil { 139 return 0, 0, err 140 } 141 if isList { 142 return 0, 0, fmt.Errorf("%w: must be a string, instead of a list", ErrParse) 143 } 144 return 145 } 146 func StringOfLen(payload []byte, pos, expectedLen int) (dataPos int, err error) { 147 dataPos, dataLen, err := String(payload, pos) 148 if err != nil { 149 return 0, err 150 } 151 if dataLen != expectedLen { 152 return 0, fmt.Errorf("%w: expected string of len %d, got %d", ErrParse, expectedLen, dataLen) 153 } 154 return 155 } 156 157 // U64 parses uint64 number from given payload at given position 158 func U64(payload []byte, pos int) (int, uint64, error) { 159 dataPos, dataLen, isList, err := Prefix(payload, pos) 160 if err != nil { 161 return 0, 0, err 162 } 163 if isList { 164 return 0, 0, fmt.Errorf("%w: uint64 must be a string, not isList", ErrParse) 165 } 166 if dataLen > 8 { 167 return 0, 0, fmt.Errorf("%w: uint64 must not be more than 8 bytes long, got %d", ErrParse, dataLen) 168 } 169 if dataLen > 0 && payload[dataPos] == 0 { 170 return 0, 0, fmt.Errorf("%w: integer encoding for RLP must not have leading zeros: %x", ErrParse, payload[dataPos:dataPos+dataLen]) 171 } 172 var r uint64 173 for _, b := range payload[dataPos : dataPos+dataLen] { 174 r = (r << 8) | uint64(b) 175 } 176 return dataPos + dataLen, r, nil 177 } 178 179 // U32 parses uint64 number from given payload at given position 180 func U32(payload []byte, pos int) (int, uint32, error) { 181 dataPos, dataLen, isList, err := Prefix(payload, pos) 182 if err != nil { 183 return 0, 0, err 184 } 185 if isList { 186 return 0, 0, fmt.Errorf("%w: uint32 must be a string, not isList", ErrParse) 187 } 188 if dataLen > 4 { 189 return 0, 0, fmt.Errorf("%w: uint32 must not be more than 4 bytes long, got %d", ErrParse, dataLen) 190 } 191 if dataLen > 0 && payload[dataPos] == 0 { 192 return 0, 0, fmt.Errorf("%w: integer encoding for RLP must not have leading zeros: %x", ErrParse, payload[dataPos:dataPos+dataLen]) 193 } 194 var r uint32 195 for _, b := range payload[dataPos : dataPos+dataLen] { 196 r = (r << 8) | uint32(b) 197 } 198 return dataPos + dataLen, r, nil 199 } 200 201 // U256 parses uint256 number from given payload at given position 202 func U256(payload []byte, pos int, x *uint256.Int) (int, error) { 203 dataPos, dataLen, err := String(payload, pos) 204 if err != nil { 205 return 0, err 206 } 207 if dataLen > 32 { 208 return 0, fmt.Errorf("%w: uint256 must not be more than 32 bytes long, got %d", ErrParse, dataLen) 209 } 210 if dataLen > 0 && payload[dataPos] == 0 { 211 return 0, fmt.Errorf("%w: integer encoding for RLP must not have leading zeros: %x", ErrParse, payload[dataPos:dataPos+dataLen]) 212 } 213 x.SetBytes(payload[dataPos : dataPos+dataLen]) 214 return dataPos + dataLen, nil 215 } 216 217 func U256Len(z *uint256.Int) int { 218 if z == nil { 219 return 1 220 } 221 nBits := z.BitLen() 222 if nBits == 0 { 223 return 1 224 } 225 if nBits <= 7 { 226 return 1 227 } 228 return 1 + common.BitLenToByteLen(nBits) 229 } 230 231 func ParseHash(payload []byte, pos int, hashbuf []byte) (int, error) { 232 pos, err := StringOfLen(payload, pos, 32) 233 if err != nil { 234 return 0, fmt.Errorf("%s: hash len: %w", ParseHashErrorPrefix, err) 235 } 236 copy(hashbuf, payload[pos:pos+32]) 237 return pos + 32, nil 238 } 239 240 const ParseHashErrorPrefix = "parse hash payload" 241 242 const ParseAnnouncementsErrorPrefix = "parse announcement payload" 243 244 func ParseAnnouncements(payload []byte, pos int) ([]byte, []uint32, []byte, int, error) { 245 pos, totalLen, err := List(payload, pos) 246 if err != nil { 247 return nil, nil, nil, pos, err 248 } 249 if pos+totalLen > len(payload) { 250 return nil, nil, nil, pos, fmt.Errorf("%s: totalLen %d is beyond the end of payload", ParseAnnouncementsErrorPrefix, totalLen) 251 } 252 pos, typesLen, err := String(payload, pos) 253 if err != nil { 254 return nil, nil, nil, pos, err 255 } 256 if pos+typesLen > len(payload) { 257 return nil, nil, nil, pos, fmt.Errorf("%s: typesLen %d is beyond the end of payload", ParseAnnouncementsErrorPrefix, typesLen) 258 } 259 types := payload[pos : pos+typesLen] 260 pos += typesLen 261 pos, sizesLen, err := List(payload, pos) 262 if err != nil { 263 return nil, nil, nil, pos, err 264 } 265 if pos+sizesLen > len(payload) { 266 return nil, nil, nil, pos, fmt.Errorf("%s: sizesLen %d is beyond the end of payload", ParseAnnouncementsErrorPrefix, sizesLen) 267 } 268 sizes := make([]uint32, typesLen) 269 for i := 0; i < len(sizes); i++ { 270 if pos, sizes[i], err = U32(payload, pos); err != nil { 271 return nil, nil, nil, pos, err 272 } 273 } 274 pos, hashesLen, err := List(payload, pos) 275 if err != nil { 276 return nil, nil, nil, pos, err 277 } 278 if pos+hashesLen > len(payload) { 279 return nil, nil, nil, pos, fmt.Errorf("%s: hashesLen %d is beyond the end of payload", ParseAnnouncementsErrorPrefix, hashesLen) 280 } 281 hashes := make([]byte, 32*(hashesLen/33)) 282 for i := 0; i < len(hashes); i += 32 { 283 if pos, err = ParseHash(payload, pos, hashes[i:]); err != nil { 284 return nil, nil, nil, pos, err 285 } 286 } 287 return types, sizes, hashes, pos, nil 288 }