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 }