github.com/onflow/flow-go@v0.33.17/fvm/evm/emulator/state/collection.go (about)

     1  package state
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  	"math"
     9  	"runtime"
    10  
    11  	"github.com/fxamacker/cbor/v2"
    12  	"github.com/onflow/atree"
    13  )
    14  
    15  const (
    16  	storageIDSize = 16
    17  )
    18  
    19  // CollectionProvider provides access to collections
    20  type CollectionProvider struct {
    21  	rootAddr atree.Address
    22  	storage  *atree.PersistentSlabStorage
    23  }
    24  
    25  // NewCollectionProvider constructs a new CollectionProvider
    26  func NewCollectionProvider(
    27  	rootAddr atree.Address,
    28  	ledger atree.Ledger,
    29  ) (*CollectionProvider, error) {
    30  	// empty address is not allowed (causes issues with atree)
    31  	if rootAddr == atree.AddressUndefined {
    32  		return nil, fmt.Errorf("empty address as root is not allowed")
    33  	}
    34  	baseStorage := atree.NewLedgerBaseStorage(ledger)
    35  	storage, err := NewPersistentSlabStorage(baseStorage)
    36  	return &CollectionProvider{
    37  		rootAddr: rootAddr,
    38  		storage:  storage,
    39  	}, err
    40  }
    41  
    42  // CollectionByID returns the collection by collection ID
    43  //
    44  // if no collection is found with that collection id, it return error
    45  // Warning: this method should only used only once for each collection and
    46  // the returned pointer should be kept for the future.
    47  // calling twice for the same collection might result in odd-behaviours
    48  // currently collection provider doesn't do any internal caching to protect aginast these cases
    49  func (cp *CollectionProvider) CollectionByID(collectionID []byte) (*Collection, error) {
    50  	storageID, err := atree.NewStorageIDFromRawBytes(collectionID)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  	// sanity check the storage ID address
    55  	if storageID.Address != cp.rootAddr {
    56  		return nil, fmt.Errorf("root address mismatch %x != %x", storageID.Address, cp.rootAddr)
    57  	}
    58  
    59  	omap, err := atree.NewMapWithRootID(cp.storage, storageID, atree.NewDefaultDigesterBuilder())
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	return &Collection{
    64  		omap:         omap,
    65  		storage:      cp.storage,
    66  		collectionID: collectionID,
    67  	}, nil
    68  }
    69  
    70  // NewCollection constructs a new collection
    71  func (cp *CollectionProvider) NewCollection() (*Collection, error) {
    72  	omap, err := atree.NewMap(cp.storage, cp.rootAddr, atree.NewDefaultDigesterBuilder(), emptyTypeInfo{})
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  	storageIDBytes := make([]byte, storageIDSize)
    77  	_, err = omap.StorageID().ToRawBytes(storageIDBytes)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	return &Collection{
    82  		storage:      cp.storage,
    83  		omap:         omap,
    84  		collectionID: storageIDBytes, // we reuse the storageID bytes as collectionID
    85  	}, nil
    86  }
    87  
    88  // Commit commits all changes to the collections with changes
    89  func (cp *CollectionProvider) Commit() error {
    90  	return cp.storage.FastCommit(runtime.NumCPU())
    91  }
    92  
    93  // Collection provides a persistent and compact way of storing key/value pairs
    94  // each collection has a unique collectionID that can be used to fetch the collection
    95  //
    96  // TODO(ramtin): we might not need any extra hashing on the atree side
    97  // and optimize this to just use the key given the keys are hashed ?
    98  type Collection struct {
    99  	omap         *atree.OrderedMap
   100  	storage      *atree.PersistentSlabStorage
   101  	collectionID []byte
   102  }
   103  
   104  // CollectionID returns the unique id for the collection
   105  func (c *Collection) CollectionID() []byte {
   106  	return c.collectionID
   107  }
   108  
   109  // Get gets the value for the given key
   110  //
   111  // if key doesn't exist it returns nil (no error)
   112  func (c *Collection) Get(key []byte) ([]byte, error) {
   113  	data, err := c.omap.Get(compare, hashInputProvider, NewByteStringValue(key))
   114  	if err != nil {
   115  		var keyNotFoundError *atree.KeyNotFoundError
   116  		if errors.As(err, &keyNotFoundError) {
   117  			return nil, nil
   118  		}
   119  		return nil, err
   120  	}
   121  
   122  	value, err := data.StoredValue(c.omap.Storage)
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  
   127  	return value.(ByteStringValue).Bytes(), nil
   128  }
   129  
   130  // Set sets the value for the given key
   131  //
   132  // if a value already stored at the given key it replaces the value
   133  func (c *Collection) Set(key, value []byte) error {
   134  	existingValueStorable, err := c.omap.Set(compare, hashInputProvider, NewByteStringValue(key), NewByteStringValue(value))
   135  	if err != nil {
   136  		return err
   137  	}
   138  
   139  	if id, ok := existingValueStorable.(atree.StorageIDStorable); ok {
   140  		// NOTE: deep remove isn't necessary because value is ByteStringValue (not container)
   141  		err := c.storage.Remove(atree.StorageID(id))
   142  		if err != nil {
   143  			return err
   144  		}
   145  	}
   146  	return nil
   147  }
   148  
   149  // Remove removes a key from the collection
   150  //
   151  // if the key doesn't exist it return no error
   152  func (c *Collection) Remove(key []byte) error {
   153  	_, existingValueStorable, err := c.omap.Remove(compare, hashInputProvider, NewByteStringValue(key))
   154  	if err != nil {
   155  		var keyNotFoundError *atree.KeyNotFoundError
   156  		if errors.As(err, &keyNotFoundError) {
   157  			return nil
   158  		}
   159  		return err
   160  	}
   161  
   162  	if id, ok := existingValueStorable.(atree.StorageIDStorable); ok {
   163  		// NOTE: deep remove isn't necessary because value is ByteStringValue (not container)
   164  		err := c.storage.Remove(atree.StorageID(id))
   165  		if err != nil {
   166  			return err
   167  		}
   168  	}
   169  	return nil
   170  }
   171  
   172  // Destroy destroys the whole collection
   173  func (c *Collection) Destroy() ([][]byte, error) {
   174  	var cachedErr error
   175  	keys := make([][]byte, c.omap.Count())
   176  	i := 0
   177  	err := c.omap.PopIterate(func(keyStorable atree.Storable, valueStorable atree.Storable) {
   178  		if id, ok := valueStorable.(atree.StorageIDStorable); ok {
   179  			err := c.storage.Remove(atree.StorageID(id))
   180  			if err != nil && cachedErr == nil {
   181  				cachedErr = err
   182  			}
   183  		}
   184  		key, err := keyStorable.StoredValue(c.omap.Storage)
   185  		if err != nil && cachedErr == nil {
   186  			cachedErr = err
   187  		}
   188  		keys[i] = key.(ByteStringValue).Bytes()
   189  		i++
   190  	})
   191  	if cachedErr != nil {
   192  		return keys, cachedErr
   193  	}
   194  	if err != nil {
   195  		return keys, err
   196  	}
   197  	return keys, c.storage.Remove(c.omap.StorageID())
   198  }
   199  
   200  type ByteStringValue struct {
   201  	data []byte
   202  	size uint32
   203  }
   204  
   205  var _ atree.Value = &ByteStringValue{}
   206  var _ atree.Storable = &ByteStringValue{}
   207  
   208  func NewByteStringValue(data []byte) ByteStringValue {
   209  	size := atree.GetUintCBORSize(uint64(len(data))) + uint32(len(data))
   210  	return ByteStringValue{data: data, size: size}
   211  }
   212  
   213  func (v ByteStringValue) ChildStorables() []atree.Storable {
   214  	return nil
   215  }
   216  
   217  func (v ByteStringValue) StoredValue(_ atree.SlabStorage) (atree.Value, error) {
   218  	return v, nil
   219  }
   220  
   221  func (v ByteStringValue) Storable(storage atree.SlabStorage, address atree.Address, maxInlineSize uint64) (atree.Storable, error) {
   222  	if uint64(v.ByteSize()) <= maxInlineSize {
   223  		return v, nil
   224  	}
   225  
   226  	// Create StorableSlab
   227  	id, err := storage.GenerateStorageID(address)
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  
   232  	slab := &atree.StorableSlab{
   233  		StorageID: id,
   234  		Storable:  v,
   235  	}
   236  
   237  	// Store StorableSlab in storage
   238  	err = storage.Store(id, slab)
   239  	if err != nil {
   240  		return nil, err
   241  	}
   242  
   243  	// Return storage id as storable
   244  	return atree.StorageIDStorable(id), nil
   245  }
   246  
   247  func (v ByteStringValue) Encode(enc *atree.Encoder) error {
   248  	return enc.CBOR.EncodeBytes(v.data)
   249  }
   250  
   251  func (v ByteStringValue) getHashInput(scratch []byte) ([]byte, error) {
   252  
   253  	const cborTypeByteString = 0x40
   254  
   255  	buf := scratch
   256  	if uint32(len(buf)) < v.size {
   257  		buf = make([]byte, v.size)
   258  	} else {
   259  		buf = buf[:v.size]
   260  	}
   261  
   262  	slen := len(v.data)
   263  
   264  	if slen <= 23 {
   265  		buf[0] = cborTypeByteString | byte(slen)
   266  		copy(buf[1:], v.data)
   267  		return buf, nil
   268  	}
   269  
   270  	if slen <= math.MaxUint8 {
   271  		buf[0] = cborTypeByteString | byte(24)
   272  		buf[1] = byte(slen)
   273  		copy(buf[2:], v.data)
   274  		return buf, nil
   275  	}
   276  
   277  	if slen <= math.MaxUint16 {
   278  		buf[0] = cborTypeByteString | byte(25)
   279  		binary.BigEndian.PutUint16(buf[1:], uint16(slen))
   280  		copy(buf[3:], v.data)
   281  		return buf, nil
   282  	}
   283  
   284  	if slen <= math.MaxUint32 {
   285  		buf[0] = cborTypeByteString | byte(26)
   286  		binary.BigEndian.PutUint32(buf[1:], uint32(slen))
   287  		copy(buf[5:], v.data)
   288  		return buf, nil
   289  	}
   290  
   291  	buf[0] = cborTypeByteString | byte(27)
   292  	binary.BigEndian.PutUint64(buf[1:], uint64(slen))
   293  	copy(buf[9:], v.data)
   294  	return buf, nil
   295  }
   296  
   297  func (v ByteStringValue) ByteSize() uint32 {
   298  	return v.size
   299  }
   300  
   301  func (v ByteStringValue) String() string {
   302  	return string(v.data)
   303  }
   304  
   305  func (v ByteStringValue) Bytes() []byte {
   306  	return v.data
   307  }
   308  
   309  func decodeStorable(dec *cbor.StreamDecoder, _ atree.StorageID) (atree.Storable, error) {
   310  	t, err := dec.NextType()
   311  	if err != nil {
   312  		return nil, err
   313  	}
   314  
   315  	switch t {
   316  	case cbor.ByteStringType:
   317  		s, err := dec.DecodeBytes()
   318  		if err != nil {
   319  			return nil, err
   320  		}
   321  		return NewByteStringValue(s), nil
   322  
   323  	case cbor.TagType:
   324  		tagNumber, err := dec.DecodeTagNumber()
   325  		if err != nil {
   326  			return nil, err
   327  		}
   328  
   329  		switch tagNumber {
   330  
   331  		case atree.CBORTagStorageID:
   332  			return atree.DecodeStorageIDStorable(dec)
   333  
   334  		default:
   335  			return nil, fmt.Errorf("invalid tag number %d", tagNumber)
   336  		}
   337  
   338  	default:
   339  		return nil, fmt.Errorf("invalid cbor type %s for storable", t)
   340  	}
   341  }
   342  
   343  func compare(storage atree.SlabStorage, value atree.Value, storable atree.Storable) (bool, error) {
   344  	switch v := value.(type) {
   345  
   346  	case ByteStringValue:
   347  		other, ok := storable.(ByteStringValue)
   348  		if ok {
   349  			return bytes.Equal(other.data, v.data), nil
   350  		}
   351  
   352  		// Retrieve value from storage
   353  		otherValue, err := storable.StoredValue(storage)
   354  		if err != nil {
   355  			return false, err
   356  		}
   357  		other, ok = otherValue.(ByteStringValue)
   358  		if ok {
   359  			return bytes.Equal(other.data, v.data), nil
   360  		}
   361  
   362  		return false, nil
   363  	}
   364  
   365  	return false, fmt.Errorf("value %T not supported for comparison", value)
   366  }
   367  
   368  func hashInputProvider(value atree.Value, buffer []byte) ([]byte, error) {
   369  	switch v := value.(type) {
   370  	case ByteStringValue:
   371  		return v.getHashInput(buffer)
   372  	}
   373  
   374  	return nil, fmt.Errorf("value %T not supported for hash input", value)
   375  }
   376  
   377  func NewPersistentSlabStorage(baseStorage atree.BaseStorage) (*atree.PersistentSlabStorage, error) {
   378  	encMode, err := cbor.EncOptions{}.EncMode()
   379  	if err != nil {
   380  		return nil, err
   381  	}
   382  
   383  	decMode, err := cbor.DecOptions{}.DecMode()
   384  	if err != nil {
   385  		return nil, err
   386  	}
   387  
   388  	return atree.NewPersistentSlabStorage(
   389  		baseStorage,
   390  		encMode,
   391  		decMode,
   392  		decodeStorable,
   393  		decodeTypeInfo,
   394  	), nil
   395  }
   396  
   397  type emptyTypeInfo struct{}
   398  
   399  var _ atree.TypeInfo = emptyTypeInfo{}
   400  
   401  func (emptyTypeInfo) Encode(e *cbor.StreamEncoder) error {
   402  	return e.EncodeNil()
   403  }
   404  
   405  func (i emptyTypeInfo) Equal(other atree.TypeInfo) bool {
   406  	_, ok := other.(emptyTypeInfo)
   407  	return ok
   408  }
   409  
   410  func decodeTypeInfo(dec *cbor.StreamDecoder) (atree.TypeInfo, error) {
   411  	ty, err := dec.NextType()
   412  	if err != nil {
   413  		return nil, err
   414  	}
   415  	switch ty {
   416  	case cbor.NilType:
   417  		err := dec.DecodeNil()
   418  		if err != nil {
   419  			return nil, err
   420  		}
   421  		return emptyTypeInfo{}, nil
   422  	default:
   423  	}
   424  
   425  	return nil, fmt.Errorf("not supported type info")
   426  }