github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/evm/emulator/state/base.go (about) 1 package state 2 3 import ( 4 "fmt" 5 "math/big" 6 7 "github.com/onflow/atree" 8 gethCommon "github.com/onflow/go-ethereum/common" 9 gethTypes "github.com/onflow/go-ethereum/core/types" 10 11 "github.com/onflow/flow-go/fvm/evm/types" 12 "github.com/onflow/flow-go/model/flow" 13 ) 14 15 const ( 16 // AccountsStorageIDKey is the path where we store the collection ID for accounts 17 AccountsStorageIDKey = "AccountsStorageIDKey" 18 // CodesStorageIDKey is the path where we store the collection ID for codes 19 CodesStorageIDKey = "CodesStorageIDKey" 20 ) 21 22 // BaseView implements a types.BaseView 23 // it acts as the base layer of state queries for the stateDB 24 // it stores accounts, codes and storage slots. 25 // 26 // under the hood it uses a set of collections, 27 // one for account's meta data, one for codes 28 // and one for each of account storage space. 29 type BaseView struct { 30 rootAddress flow.Address 31 ledger atree.Ledger 32 collectionProvider *CollectionProvider 33 34 // collections 35 accounts *Collection 36 codes *Collection 37 slots map[gethCommon.Address]*Collection 38 39 // cached values 40 cachedAccounts map[gethCommon.Address]*Account 41 cachedCodes map[gethCommon.Address][]byte 42 cachedSlots map[types.SlotAddress]gethCommon.Hash 43 44 // flags 45 accountSetupOnCommit bool 46 codeSetupOnCommit bool 47 } 48 49 var _ types.BaseView = &BaseView{} 50 51 // NewBaseView constructs a new base view 52 func NewBaseView(ledger atree.Ledger, rootAddress flow.Address) (*BaseView, error) { 53 cp, err := NewCollectionProvider(atree.Address(rootAddress), ledger) 54 if err != nil { 55 return nil, err 56 } 57 58 view := &BaseView{ 59 ledger: ledger, 60 rootAddress: rootAddress, 61 collectionProvider: cp, 62 63 slots: make(map[gethCommon.Address]*Collection), 64 65 cachedAccounts: make(map[gethCommon.Address]*Account), 66 cachedCodes: make(map[gethCommon.Address][]byte), 67 cachedSlots: make(map[types.SlotAddress]gethCommon.Hash), 68 } 69 70 // fetch the account collection, if not exist, create one 71 view.accounts, view.accountSetupOnCommit, err = view.fetchOrCreateCollection(AccountsStorageIDKey) 72 if err != nil { 73 return nil, err 74 } 75 76 // fetch the code collection, if not exist, create one 77 view.codes, view.codeSetupOnCommit, err = view.fetchOrCreateCollection(CodesStorageIDKey) 78 if err != nil { 79 return nil, err 80 } 81 82 return view, nil 83 } 84 85 // Exist returns true if the address exist in the state 86 func (v *BaseView) Exist(addr gethCommon.Address) (bool, error) { 87 acc, err := v.getAccount(addr) 88 return acc != nil, err 89 } 90 91 // IsCreated returns true if the address has been created in the context of this transaction 92 func (v *BaseView) IsCreated(gethCommon.Address) bool { 93 return false 94 } 95 96 // HasSelfDestructed returns true if an address is flagged for destruction at the end of transaction 97 func (v *BaseView) HasSelfDestructed(gethCommon.Address) (bool, *big.Int) { 98 return false, new(big.Int) 99 } 100 101 // GetBalance returns the balance of an address 102 // 103 // for non-existent accounts it returns a balance of zero 104 func (v *BaseView) GetBalance(addr gethCommon.Address) (*big.Int, error) { 105 acc, err := v.getAccount(addr) 106 bal := big.NewInt(0) 107 if acc != nil { 108 bal = acc.Balance 109 } 110 return bal, err 111 } 112 113 // GetNonce returns the nonce of an address 114 // 115 // for non-existent accounts it returns zero 116 func (v *BaseView) GetNonce(addr gethCommon.Address) (uint64, error) { 117 acc, err := v.getAccount(addr) 118 nonce := uint64(0) 119 if acc != nil { 120 nonce = acc.Nonce 121 } 122 return nonce, err 123 } 124 125 // GetCode returns the code of an address 126 // 127 // for non-existent accounts or accounts without a code (e.g. EOAs) it returns nil 128 func (v *BaseView) GetCode(addr gethCommon.Address) ([]byte, error) { 129 return v.getCode(addr) 130 } 131 132 // GetCodeHash returns the code hash of an address 133 // 134 // for non-existent accounts it returns gethCommon.Hash{} 135 // and for accounts without a code (e.g. EOAs) it returns default empty 136 // hash value (gethTypes.EmptyCodeHash) 137 func (v *BaseView) GetCodeHash(addr gethCommon.Address) (gethCommon.Hash, error) { 138 acc, err := v.getAccount(addr) 139 codeHash := gethCommon.Hash{} 140 if acc != nil { 141 codeHash = acc.CodeHash 142 } 143 return codeHash, err 144 } 145 146 // GetCodeSize returns the code size of an address 147 // 148 // for non-existent accounts or accounts without a code (e.g. EOAs) it returns zero 149 func (v *BaseView) GetCodeSize(addr gethCommon.Address) (int, error) { 150 code, err := v.GetCode(addr) 151 return len(code), err 152 } 153 154 // GetState returns values for a slot in the main storage 155 // 156 // for non-existent slots it returns the default empty hash value (gethTypes.EmptyCodeHash) 157 func (v *BaseView) GetState(sk types.SlotAddress) (gethCommon.Hash, error) { 158 return v.getSlot(sk) 159 } 160 161 // UpdateSlot updates the value for a slot 162 func (v *BaseView) UpdateSlot(sk types.SlotAddress, value gethCommon.Hash) error { 163 return v.storeSlot(sk, value) 164 } 165 166 // GetRefund returns the total amount of (gas) refund 167 // 168 // this method returns the value of zero 169 func (v *BaseView) GetRefund() uint64 { 170 return 0 171 } 172 173 // GetTransientState returns values for an slot transient storage 174 // 175 // transient storage is not a functionality for the base view so it always 176 // returns the default value for non-existent slots 177 func (v *BaseView) GetTransientState(types.SlotAddress) gethCommon.Hash { 178 return gethCommon.Hash{} 179 } 180 181 // AddressInAccessList checks if an address is in the access list 182 // 183 // access list control is not a functionality of the base view 184 // it always returns false 185 func (v *BaseView) AddressInAccessList(gethCommon.Address) bool { 186 return false 187 } 188 189 // SlotInAccessList checks if a slot is in the access list 190 // 191 // access list control is not a functionality of the base view 192 // it always returns false 193 func (v *BaseView) SlotInAccessList(types.SlotAddress) (addressOk bool, slotOk bool) { 194 return false, false 195 } 196 197 // CreateAccount creates a new account 198 func (v *BaseView) CreateAccount( 199 addr gethCommon.Address, 200 balance *big.Int, 201 nonce uint64, 202 code []byte, 203 codeHash gethCommon.Hash, 204 ) error { 205 var colID []byte 206 // if is an smart contract account 207 if len(code) > 0 { 208 err := v.updateAccountCode(addr, code, codeHash) 209 if err != nil { 210 return err 211 } 212 } 213 214 // create a new account and store it 215 acc := NewAccount(addr, balance, nonce, codeHash, colID) 216 217 // no need to update the cache , storeAccount would update the cache 218 return v.storeAccount(acc) 219 } 220 221 // UpdateAccount updates an account's meta data 222 func (v *BaseView) UpdateAccount( 223 addr gethCommon.Address, 224 balance *big.Int, 225 nonce uint64, 226 code []byte, 227 codeHash gethCommon.Hash, 228 ) error { 229 acc, err := v.getAccount(addr) 230 if err != nil { 231 return err 232 } 233 // if update is called on a non existing account 234 // we gracefully call the create account 235 // TODO: but we might need to revisit this action in the future 236 if acc == nil { 237 return v.CreateAccount(addr, balance, nonce, code, codeHash) 238 } 239 240 // update account code 241 err = v.updateAccountCode(addr, code, codeHash) 242 if err != nil { 243 return err 244 } 245 // TODO: maybe purge the state in the future as well 246 // currently the behaviour of stateDB doesn't purge the data 247 // We don't need to check if the code is empty and we purge the state 248 // this is not possible right now. 249 250 newAcc := NewAccount(addr, balance, nonce, codeHash, acc.CollectionID) 251 // no need to update the cache , storeAccount would update the cache 252 return v.storeAccount(newAcc) 253 } 254 255 // DeleteAccount deletes an account's meta data, code, and 256 // storage slots associated with that address 257 func (v *BaseView) DeleteAccount(addr gethCommon.Address) error { 258 // 1. check account exists 259 acc, err := v.getAccount(addr) 260 if err != nil { 261 return err 262 } 263 if acc == nil { 264 return fmt.Errorf("account doesn't exist to be deleted") 265 } 266 267 // 2. remove the code 268 if acc.HasCode() { 269 err = v.updateAccountCode(addr, nil, gethTypes.EmptyCodeHash) 270 if err != nil { 271 return err 272 } 273 } 274 275 // 3. update the cache 276 delete(v.cachedAccounts, addr) 277 278 // 4. collections 279 err = v.accounts.Remove(addr.Bytes()) 280 if err != nil { 281 return err 282 } 283 284 // 5. remove storage slots 285 if len(acc.CollectionID) > 0 { 286 col, found := v.slots[addr] 287 if !found { 288 col, err = v.collectionProvider.CollectionByID(acc.CollectionID) 289 if err != nil { 290 return err 291 } 292 } 293 // delete all slots related to this account (eip-6780) 294 keys, err := col.Destroy() 295 if err != nil { 296 return err 297 } 298 299 delete(v.slots, addr) 300 301 for _, key := range keys { 302 delete(v.cachedSlots, types.SlotAddress{ 303 Address: addr, 304 Key: gethCommon.BytesToHash(key), 305 }) 306 } 307 } 308 return nil 309 } 310 311 // Commit commits the changes to the underlying storage layers 312 func (v *BaseView) Commit() error { 313 // commit collection changes 314 err := v.collectionProvider.Commit() 315 if err != nil { 316 return err 317 } 318 319 // if this is the first time we are setting up an 320 // account collection, store its collection id. 321 if v.accountSetupOnCommit { 322 err = v.ledger.SetValue(v.rootAddress[:], []byte(AccountsStorageIDKey), v.accounts.CollectionID()) 323 if err != nil { 324 return err 325 } 326 v.accountSetupOnCommit = false 327 328 } 329 330 // if this is the first time we are setting up an 331 // code collection, store its collection id. 332 if v.codeSetupOnCommit { 333 err = v.ledger.SetValue(v.rootAddress[:], []byte(CodesStorageIDKey), v.codes.CollectionID()) 334 if err != nil { 335 return err 336 } 337 v.codeSetupOnCommit = false 338 } 339 return nil 340 } 341 342 // NumberOfContracts returns the number of unique contracts 343 func (v *BaseView) NumberOfContracts() uint64 { 344 return v.codes.Size() 345 } 346 347 // NumberOfContracts returns the number of accounts 348 func (v *BaseView) NumberOfAccounts() uint64 { 349 return v.accounts.Size() 350 } 351 352 func (v *BaseView) fetchOrCreateCollection(path string) (collection *Collection, created bool, error error) { 353 collectionID, err := v.ledger.GetValue(v.rootAddress[:], []byte(path)) 354 if err != nil { 355 return nil, false, err 356 } 357 if len(collectionID) == 0 { 358 collection, err = v.collectionProvider.NewCollection() 359 return collection, true, err 360 } 361 collection, err = v.collectionProvider.CollectionByID(collectionID) 362 return collection, false, err 363 } 364 365 func (v *BaseView) getAccount(addr gethCommon.Address) (*Account, error) { 366 // check cached accounts first 367 acc, found := v.cachedAccounts[addr] 368 if found { 369 return acc, nil 370 } 371 372 // then collect it from the account collection 373 data, err := v.accounts.Get(addr.Bytes()) 374 if err != nil { 375 return nil, err 376 } 377 // decode it 378 acc, err = DecodeAccount(data) 379 if err != nil { 380 return nil, err 381 } 382 // cache it 383 if acc != nil { 384 v.cachedAccounts[addr] = acc 385 } 386 return acc, nil 387 } 388 389 func (v *BaseView) storeAccount(acc *Account) error { 390 data, err := acc.Encode() 391 if err != nil { 392 return err 393 } 394 // update the cache 395 v.cachedAccounts[acc.Address] = acc 396 return v.accounts.Set(acc.Address.Bytes(), data) 397 } 398 399 func (v *BaseView) getCode(addr gethCommon.Address) ([]byte, error) { 400 // check the cache first 401 code, found := v.cachedCodes[addr] 402 if found { 403 return code, nil 404 } 405 406 // get account 407 acc, err := v.getAccount(addr) 408 if err != nil { 409 return nil, err 410 } 411 412 if acc == nil || !acc.HasCode() { 413 return nil, nil 414 } 415 416 // collect the container from the code collection by codeHash 417 encoded, err := v.codes.Get(acc.CodeHash.Bytes()) 418 if err != nil { 419 return nil, err 420 } 421 if len(encoded) == 0 { 422 return nil, nil 423 } 424 425 codeCont, err := CodeContainerFromEncoded(encoded) 426 if err != nil { 427 return nil, err 428 } 429 code = codeCont.Code() 430 if len(code) > 0 { 431 v.cachedCodes[addr] = code 432 } 433 return code, nil 434 } 435 436 func (v *BaseView) updateAccountCode(addr gethCommon.Address, code []byte, codeHash gethCommon.Hash) error { 437 // get account 438 acc, err := v.getAccount(addr) 439 if err != nil { 440 return err 441 } 442 // if is a new account 443 if acc == nil { 444 if len(code) == 0 { 445 return nil 446 } 447 v.cachedCodes[addr] = code 448 return v.addCode(code, codeHash) 449 } 450 451 // skip if is the same code 452 if acc.CodeHash == codeHash { 453 return nil 454 } 455 456 // clean old code first if exist 457 if acc.HasCode() { 458 delete(v.cachedCodes, addr) 459 err = v.removeCode(acc.CodeHash) 460 if err != nil { 461 return err 462 } 463 } 464 465 // add new code 466 if len(code) == 0 { 467 return nil 468 } 469 v.cachedCodes[addr] = code 470 return v.addCode(code, codeHash) 471 } 472 473 func (v *BaseView) removeCode(codeHash gethCommon.Hash) error { 474 encoded, err := v.codes.Get(codeHash.Bytes()) 475 if err != nil { 476 return err 477 } 478 if len(encoded) == 0 { 479 return nil 480 } 481 482 cc, err := CodeContainerFromEncoded(encoded) 483 if err != nil { 484 return err 485 } 486 if cc.DecRefCount() { 487 return v.codes.Remove(codeHash.Bytes()) 488 } 489 return v.codes.Set(codeHash.Bytes(), cc.Encode()) 490 } 491 492 func (v *BaseView) addCode(code []byte, codeHash gethCommon.Hash) error { 493 encoded, err := v.codes.Get(codeHash.Bytes()) 494 if err != nil { 495 return err 496 } 497 // if is the first time the code is getting deployed 498 if len(encoded) == 0 { 499 return v.codes.Set(codeHash.Bytes(), NewCodeContainer(code).Encode()) 500 } 501 502 // otherwise update the cc 503 cc, err := CodeContainerFromEncoded(encoded) 504 if err != nil { 505 return err 506 } 507 cc.IncRefCount() 508 return v.codes.Set(codeHash.Bytes(), cc.Encode()) 509 } 510 511 func (v *BaseView) getSlot(sk types.SlotAddress) (gethCommon.Hash, error) { 512 value, found := v.cachedSlots[sk] 513 if found { 514 return value, nil 515 } 516 517 acc, err := v.getAccount(sk.Address) 518 if err != nil { 519 return gethCommon.Hash{}, err 520 } 521 if acc == nil || len(acc.CollectionID) == 0 { 522 return gethCommon.Hash{}, nil 523 } 524 525 col, err := v.getSlotCollection(acc) 526 if err != nil { 527 return gethCommon.Hash{}, err 528 } 529 530 val, err := col.Get(sk.Key.Bytes()) 531 if err != nil { 532 return gethCommon.Hash{}, err 533 } 534 value = gethCommon.BytesToHash(val) 535 v.cachedSlots[sk] = value 536 return value, nil 537 } 538 539 func (v *BaseView) storeSlot(sk types.SlotAddress, data gethCommon.Hash) error { 540 acc, err := v.getAccount(sk.Address) 541 if err != nil { 542 return err 543 } 544 if acc == nil { 545 return fmt.Errorf("slot belongs to a non-existing account") 546 } 547 if !acc.HasCode() { 548 return fmt.Errorf("slot belongs to a non-smart contract account") 549 } 550 col, err := v.getSlotCollection(acc) 551 if err != nil { 552 return err 553 } 554 555 emptyValue := gethCommon.Hash{} 556 if data == emptyValue { 557 delete(v.cachedSlots, sk) 558 return col.Remove(sk.Key.Bytes()) 559 } 560 v.cachedSlots[sk] = data 561 return col.Set(sk.Key.Bytes(), data.Bytes()) 562 } 563 564 func (v *BaseView) getSlotCollection(acc *Account) (*Collection, error) { 565 var err error 566 567 if len(acc.CollectionID) == 0 { 568 // create a new collection for slots 569 col, err := v.collectionProvider.NewCollection() 570 if err != nil { 571 return nil, err 572 } 573 // cache collection 574 v.slots[acc.Address] = col 575 // update account's collection ID 576 acc.CollectionID = col.CollectionID() 577 err = v.storeAccount(acc) 578 if err != nil { 579 return nil, err 580 } 581 return col, nil 582 } 583 584 col, found := v.slots[acc.Address] 585 if !found { 586 col, err = v.collectionProvider.CollectionByID(acc.CollectionID) 587 if err != nil { 588 return nil, err 589 } 590 v.slots[acc.Address] = col 591 } 592 return col, nil 593 }