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  }