github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/cmd/util/ledger/reporters/atree_decode.go (about) 1 package reporters 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "math" 8 9 "github.com/fxamacker/cbor/v2" 10 ) 11 12 const ( 13 versionAndFlagSize = 2 14 mapExtraDataLength = 3 15 storageIDSize = 16 16 digestSize = 8 17 flagIndex = 1 18 ) 19 20 const ( 21 CBORTagInlineCollisionGroup = 253 22 CBORTagExternalCollisionGroup = 254 23 ) 24 25 var ( 26 encodedInlineCollisionGroupPrefix = []byte{0xd8, CBORTagInlineCollisionGroup} 27 encodedExternalCollisionGroupPrefix = []byte{0xd8, CBORTagExternalCollisionGroup} 28 ) 29 30 var decMode = func() cbor.DecMode { 31 decMode, err := cbor.DecOptions{ 32 IntDec: cbor.IntDecConvertNone, 33 MaxArrayElements: math.MaxInt64, 34 MaxMapPairs: math.MaxInt64, 35 MaxNestedLevels: math.MaxInt16, 36 }.DecMode() 37 if err != nil { 38 panic(err) 39 } 40 return decMode 41 }() 42 43 // These functions are simplified version of decoding 44 // functions in onflow/atree. Full functionality requires 45 // Cadence package which isn't needed here. 46 47 // parseSlabMapData returns raw elements bytes. 48 func parseSlabMapData(data []byte) ([]byte, error) { 49 // Check minimum data length 50 if len(data) < versionAndFlagSize { 51 return nil, errors.New("data is too short for map data slab") 52 } 53 54 isRootSlab := isRoot(data[flagIndex]) 55 56 // Check flag for extra data 57 if isRootSlab { 58 // Decode extra data 59 var err error 60 data, err = skipMapExtraData(data, decMode) 61 if err != nil { 62 return nil, err 63 } 64 } 65 66 if len(data) < versionAndFlagSize { 67 return nil, errors.New("data is too short for map data slab") 68 } 69 70 // Check flag 71 flag := data[flagIndex] 72 mapType := getSlabMapType(flag) 73 if mapType != slabMapData && mapType != slabMapCollisionGroup { 74 return nil, fmt.Errorf( 75 "data has invalid flag 0x%x, want 0x%x or 0x%x", 76 flag, 77 maskMapData, 78 maskCollisionGroup, 79 ) 80 } 81 82 contentOffset := versionAndFlagSize 83 if !isRootSlab { 84 // Skip next storage ID for non-root slab 85 contentOffset += storageIDSize 86 } 87 88 return data[contentOffset:], nil 89 } 90 91 // getCollisionGroupCountFromSlabMapData returns collision level, 92 // number of collision groups (inline and external collision groups), 93 // and error. 94 func getCollisionGroupCountFromSlabMapData(data []byte) (collisionLevel uint, collisionGroupCount uint, err error) { 95 elements, err := parseSlabMapData(data) 96 if err != nil { 97 return 0, 0, err 98 } 99 100 collisionLevel, rawElements, err := parseRawElements(elements, decMode) 101 if err != nil { 102 return 0, 0, err 103 } 104 105 for _, rawElem := range rawElements { 106 if bytes.HasPrefix(rawElem, encodedInlineCollisionGroupPrefix) || 107 bytes.HasPrefix(rawElem, encodedExternalCollisionGroupPrefix) { 108 collisionGroupCount++ 109 } 110 } 111 112 return collisionLevel, collisionGroupCount, nil 113 } 114 115 // getInlineCollisionCountsFromSlabMapData returns collision level, inline collision counts, and error. 116 func getInlineCollisionCountsFromSlabMapData(data []byte) (collisionLevel uint, inlineCollisionCount []uint, err error) { 117 elements, err := parseSlabMapData(data) 118 if err != nil { 119 return 0, nil, err 120 } 121 122 collisionLevel, rawElements, err := parseRawElements(elements, decMode) 123 if err != nil { 124 return 0, nil, err 125 } 126 127 for _, rawElem := range rawElements { 128 if bytes.HasPrefix(rawElem, encodedInlineCollisionGroupPrefix) { 129 _, collisionElems, err := parseRawElements(rawElem, decMode) 130 if err != nil { 131 return 0, nil, err 132 } 133 inlineCollisionCount = append(inlineCollisionCount, uint(len(collisionElems))) 134 } 135 } 136 137 return collisionLevel, inlineCollisionCount, nil 138 } 139 140 func skipMapExtraData(data []byte, decMode cbor.DecMode) ([]byte, error) { 141 // Check data length 142 if len(data) < versionAndFlagSize { 143 return data, errors.New("data is too short for map extra data") 144 } 145 146 // Check flag 147 flag := data[1] 148 if !isRoot(flag) { 149 return data, fmt.Errorf("data has invalid flag 0x%x, want root flag", flag) 150 } 151 152 // Decode extra data 153 r := bytes.NewReader(data[versionAndFlagSize:]) 154 dec := decMode.NewDecoder(r) 155 156 var v []interface{} 157 err := dec.Decode(&v) 158 if err != nil { 159 return data, errors.New("failed to decode map extra data") 160 } 161 162 if len(v) != mapExtraDataLength { 163 return data, fmt.Errorf("map extra data has %d number of elements, want %d", len(v), mapExtraDataLength) 164 } 165 166 // Reslice for remaining data 167 n := dec.NumBytesRead() 168 data = data[versionAndFlagSize+n:] 169 170 return data, nil 171 } 172 173 type elements struct { 174 _ struct{} `cbor:",toarray"` 175 Level uint 176 DigestBytes []byte 177 RawElements []cbor.RawMessage 178 } 179 180 func parseRawElements(data []byte, decMode cbor.DecMode) (uint, []cbor.RawMessage, error) { 181 var elems elements 182 err := decMode.Unmarshal(data, &elems) 183 if err != nil { 184 return 0, nil, err 185 } 186 187 if len(elems.DigestBytes)%digestSize != 0 { 188 return 0, nil, fmt.Errorf("number of digest bytes is not multiple of %d", digestSize) 189 } 190 191 digestCount := len(elems.DigestBytes) / digestSize 192 193 if digestCount != len(elems.RawElements) { 194 return 0, nil, fmt.Errorf("found %d digests and %d elements", digestCount, len(elems.RawElements)) 195 } 196 197 return elems.Level, elems.RawElements, nil 198 } 199 200 // The remaining code is a subset of onflow/atree/flag.go. 201 // These functions are not exported by onflow/atree because 202 // they are implementation details. They are copied here 203 // to parse atree slabs. 204 205 type slabType int 206 207 const ( 208 slabTypeUndefined slabType = iota 209 slabArray 210 slabMap 211 slabStorable 212 ) 213 214 type slabArrayType int 215 216 const ( 217 slabArrayUndefined slabArrayType = iota 218 slabArrayData 219 slabArrayMeta 220 slabLargeImmutableArray 221 slabBasicArray 222 ) 223 224 type slabMapType int 225 226 const ( 227 slabMapUndefined slabMapType = iota 228 slabMapData 229 slabMapMeta 230 slabMapLargeEntry 231 slabMapCollisionGroup 232 ) 233 234 const ( 235 // Slab flags: 3 high bits 236 maskSlabRoot byte = 0b100_00000 237 // maskSlabHasPointers byte = 0b010_00000 238 // maskSlabAnySize byte = 0b001_00000 239 240 // Array flags: 3 low bits (4th and 5th bits are 0) 241 // maskArrayData byte = 0b000_00000 242 // maskArrayMeta byte = 0b000_00001 243 // maskLargeImmutableArray byte = 0b000_00010 // not used for now 244 // maskBasicArray byte = 0b000_00011 // used for benchmarking 245 246 // Map flags: 3 low bits (4th bit is 0, 5th bit is 1) 247 maskMapData byte = 0b000_01000 248 // maskMapMeta byte = 0b000_01001 249 // maskLargeMapEntry byte = 0b000_01010 // not used for now 250 maskCollisionGroup byte = 0b000_01011 251 252 // Storable flags: 3 low bits (4th bit is 1, 5th bit is 1) 253 // maskStorable byte = 0b000_11111 254 ) 255 256 func isRoot(f byte) bool { 257 return f&maskSlabRoot > 0 258 } 259 260 func getSlabType(f byte) slabType { 261 // Extract 4th and 5th bits for slab type. 262 dataType := (f & byte(0b000_11000)) >> 3 263 switch dataType { 264 case 0: 265 // 4th and 5th bits are 0. 266 return slabArray 267 case 1: 268 // 4th bit is 0 and 5th bit is 1. 269 return slabMap 270 case 3: 271 // 4th and 5th bit are 1. 272 return slabStorable 273 default: 274 return slabTypeUndefined 275 } 276 } 277 278 func getSlabArrayType(f byte) slabArrayType { 279 if getSlabType(f) != slabArray { 280 return slabArrayUndefined 281 } 282 283 // Extract 3 low bits for slab array type. 284 dataType := (f & byte(0b000_00111)) 285 switch dataType { 286 case 0: 287 return slabArrayData 288 case 1: 289 return slabArrayMeta 290 case 2: 291 return slabLargeImmutableArray 292 case 3: 293 return slabBasicArray 294 default: 295 return slabArrayUndefined 296 } 297 } 298 299 func getSlabMapType(f byte) slabMapType { 300 if getSlabType(f) != slabMap { 301 return slabMapUndefined 302 } 303 304 // Extract 3 low bits for slab map type. 305 dataType := (f & byte(0b000_00111)) 306 switch dataType { 307 case 0: 308 return slabMapData 309 case 1: 310 return slabMapMeta 311 case 2: 312 return slabMapLargeEntry 313 case 3: 314 return slabMapCollisionGroup 315 default: 316 return slabMapUndefined 317 } 318 }