github.com/onflow/flow-go@v0.33.17/fvm/evm/emulator/state/delta.go (about) 1 package state 2 3 import ( 4 "fmt" 5 "math/big" 6 7 gethCommon "github.com/ethereum/go-ethereum/common" 8 gethTypes "github.com/ethereum/go-ethereum/core/types" 9 gethCrypto "github.com/ethereum/go-ethereum/crypto" 10 11 "github.com/onflow/flow-go/fvm/evm/types" 12 ) 13 14 // DeltaView captures the changes to the state during the execution 15 // 16 // for most of the read calls it checks its change logs and if no record is 17 // found it would redirect the call to the parent view. 18 type DeltaView struct { 19 parent types.ReadOnlyView 20 21 // dirtyAddresses keeps a set of addresses with changes 22 dirtyAddresses map[gethCommon.Address]struct{} 23 // created keeps a set of recently created addresses 24 created map[gethCommon.Address]struct{} 25 // toBeDestructed keeps a set of addresses flagged to be destructed at the 26 // end of transaction, it also keeps the balance of the addresses before destruction 27 toBeDestructed map[gethCommon.Address]*big.Int 28 // is a flag used to track accounts that has been flagged for 29 // destruction but recreated later 30 recreated map[gethCommon.Address]struct{} 31 // balances keeps the changes to the account balances 32 balances map[gethCommon.Address]*big.Int 33 // nonces keeps the changes to the account nonces 34 nonces map[gethCommon.Address]uint64 35 // codes keeps the changes to the account codes 36 codes map[gethCommon.Address][]byte 37 // codeHashes keeps the changes to account code hashes 38 codeHashes map[gethCommon.Address]gethCommon.Hash 39 40 // slots keeps a set of slots that has been changed in this view 41 slots map[types.SlotAddress]gethCommon.Hash 42 43 // transient storage 44 transient map[types.SlotAddress]gethCommon.Hash 45 46 // access lists 47 accessListAddresses map[gethCommon.Address]struct{} 48 accessListSlots map[types.SlotAddress]struct{} 49 50 // logs 51 logs []*gethTypes.Log 52 53 // preimages 54 preimages map[gethCommon.Hash][]byte 55 56 // refund 57 refund uint64 58 } 59 60 var _ types.HotView = &DeltaView{} 61 62 // NewDeltaView constructs a new delta view 63 func NewDeltaView(parent types.ReadOnlyView) *DeltaView { 64 return &DeltaView{ 65 parent: parent, 66 67 dirtyAddresses: make(map[gethCommon.Address]struct{}), 68 created: make(map[gethCommon.Address]struct{}), 69 toBeDestructed: make(map[gethCommon.Address]*big.Int), 70 recreated: make(map[gethCommon.Address]struct{}), 71 balances: make(map[gethCommon.Address]*big.Int), 72 nonces: make(map[gethCommon.Address]uint64), 73 codes: make(map[gethCommon.Address][]byte), 74 codeHashes: make(map[gethCommon.Address]gethCommon.Hash), 75 76 slots: make(map[types.SlotAddress]gethCommon.Hash), 77 78 // for refund we just copy the data 79 refund: parent.GetRefund(), 80 } 81 } 82 83 // NewChildView constructs a new delta view having the current view as parent 84 func (d *DeltaView) NewChildView() *DeltaView { 85 return NewDeltaView(d) 86 } 87 88 // Exist returns true if address exists 89 // 90 // it also returns true for both newly created accounts or accounts that has been flagged for deletion 91 func (d *DeltaView) Exist(addr gethCommon.Address) (bool, error) { 92 _, found := d.created[addr] 93 if found { 94 return true, nil 95 } 96 _, found = d.toBeDestructed[addr] 97 if found { 98 return true, nil 99 } 100 return d.parent.Exist(addr) 101 } 102 103 // CreateAccount creates a new account for the given address 104 // 105 // if address already extists (even if destructed), carry over the balance 106 // and reset the data from the orginal account. 107 func (d *DeltaView) CreateAccount(addr gethCommon.Address) error { 108 // if is already created return 109 if d.IsCreated(addr) { 110 return nil 111 } 112 exist, err := d.Exist(addr) 113 if err != nil { 114 return err 115 } 116 if exist { 117 // check if already destructed 118 destructed, balance := d.HasSelfDestructed(addr) 119 if !destructed { 120 balance, err = d.GetBalance(addr) 121 if err != nil { 122 return err 123 } 124 err = d.SelfDestruct(addr) 125 if err != nil { 126 return err 127 } 128 } 129 130 d.nonces[addr] = 0 131 d.codes[addr] = nil 132 d.codeHashes[addr] = gethTypes.EmptyCodeHash 133 // carrying over the balance. (legacy behaviour of the Geth stateDB) 134 d.balances[addr] = balance 135 136 // flag addr as recreated, this flag helps with postponing deletion of slabs 137 // otherwise we have to iterate over all slabs of this account and set the to nil 138 d.recreated[addr] = struct{}{} 139 140 // remove slabs from cache related to this account 141 for k := range d.slots { 142 if k.Address == addr { 143 delete(d.slots, k) 144 } 145 } 146 } 147 d.dirtyAddresses[addr] = struct{}{} 148 d.created[addr] = struct{}{} 149 return nil 150 } 151 152 // IsCreated returns true if address has been created in this tx 153 func (d *DeltaView) IsCreated(addr gethCommon.Address) bool { 154 _, found := d.created[addr] 155 if found { 156 return true 157 } 158 return d.parent.IsCreated(addr) 159 } 160 161 // HasSelfDestructed returns true if address has been flagged for destruction 162 // it also returns the balance of the address before the destruction call 163 func (d *DeltaView) HasSelfDestructed(addr gethCommon.Address) (bool, *big.Int) { 164 bal, found := d.toBeDestructed[addr] 165 if found { 166 return true, bal 167 } 168 return d.parent.HasSelfDestructed(addr) 169 } 170 171 // SelfDestruct sets a flag to destruct the account at the end of transaction 172 // 173 // if an account has been created in this transaction, it would return an error 174 func (d *DeltaView) SelfDestruct(addr gethCommon.Address) error { 175 // if it has been recently created, calling self destruct is not a valid operation 176 if d.IsCreated(addr) { 177 return fmt.Errorf("invalid operation, can't selfdestruct an account that is just created") 178 } 179 180 // if it doesn't exist, return false 181 exists, err := d.Exist(addr) 182 if err != nil { 183 return err 184 } 185 if !exists { 186 return nil 187 } 188 189 // flag the account for destruction and capture the balance 190 // before destruction 191 d.toBeDestructed[addr], err = d.GetBalance(addr) 192 if err != nil { 193 return err 194 } 195 // flag the address as dirty 196 d.dirtyAddresses[addr] = struct{}{} 197 198 // set balance to zero 199 d.balances[addr] = new(big.Int) 200 return nil 201 } 202 203 // GetBalance returns the balance of the given address 204 func (d *DeltaView) GetBalance(addr gethCommon.Address) (*big.Int, error) { 205 val, found := d.balances[addr] 206 if found { 207 return val, nil 208 } 209 // if newly created and no balance is set yet 210 _, newlyCreated := d.created[addr] 211 if newlyCreated { 212 return big.NewInt(0), nil 213 } 214 return d.parent.GetBalance(addr) 215 } 216 217 // AddBalance adds the amount to the current balance of the given address 218 func (d *DeltaView) AddBalance(addr gethCommon.Address, amount *big.Int) error { 219 // if amount is 0 skip 220 if amount.Sign() == 0 { 221 return nil 222 } 223 // get the latest balance 224 orgBalance, err := d.GetBalance(addr) 225 if err != nil { 226 return err 227 } 228 // update the balance 229 newBalance := new(big.Int).Add(orgBalance, amount) 230 d.balances[addr] = newBalance 231 232 // flag the address as dirty 233 d.dirtyAddresses[addr] = struct{}{} 234 return nil 235 } 236 237 // SubBalance subtracts the amount from the current balance of the given address 238 func (d *DeltaView) SubBalance(addr gethCommon.Address, amount *big.Int) error { 239 // if amount is 0 skip 240 if amount.Sign() == 0 { 241 return nil 242 } 243 244 // get the latest balance 245 orgBalance, err := d.GetBalance(addr) 246 if err != nil { 247 return err 248 } 249 250 // update the new balance 251 newBalance := new(big.Int).Sub(orgBalance, amount) 252 253 // if new balance is negative error 254 if newBalance.Sign() < 0 { 255 return fmt.Errorf("account balance is negative %d", newBalance) 256 } 257 258 // update the balance 259 d.balances[addr] = newBalance 260 261 // flag the address as dirty 262 d.dirtyAddresses[addr] = struct{}{} 263 return nil 264 } 265 266 // GetNonce returns the nonce of the given address 267 func (d *DeltaView) GetNonce(addr gethCommon.Address) (uint64, error) { 268 val, found := d.nonces[addr] 269 if found { 270 return val, nil 271 } 272 // if newly created 273 _, newlyCreated := d.created[addr] 274 if newlyCreated { 275 return 0, nil 276 } 277 return d.parent.GetNonce(addr) 278 } 279 280 // SetNonce sets the nonce for the given address 281 func (d *DeltaView) SetNonce(addr gethCommon.Address, nonce uint64) error { 282 // update the nonce 283 d.nonces[addr] = nonce 284 285 // flag the address as dirty 286 d.dirtyAddresses[addr] = struct{}{} 287 return nil 288 } 289 290 // GetCode returns the code of the given address 291 func (d *DeltaView) GetCode(addr gethCommon.Address) ([]byte, error) { 292 code, found := d.codes[addr] 293 if found { 294 return code, nil 295 } 296 // if newly created 297 _, newlyCreated := d.created[addr] 298 if newlyCreated { 299 return nil, nil 300 } 301 return d.parent.GetCode(addr) 302 } 303 304 // GetCodeSize returns the code size of the given address 305 func (d *DeltaView) GetCodeSize(addr gethCommon.Address) (int, error) { 306 code, err := d.GetCode(addr) 307 return len(code), err 308 } 309 310 // GetCodeHash returns the code hash of the given address 311 func (d *DeltaView) GetCodeHash(addr gethCommon.Address) (gethCommon.Hash, error) { 312 codeHash, found := d.codeHashes[addr] 313 if found { 314 return codeHash, nil 315 } 316 // if newly created 317 _, newlyCreated := d.created[addr] 318 if newlyCreated { 319 return gethTypes.EmptyCodeHash, nil 320 } 321 return d.parent.GetCodeHash(addr) 322 } 323 324 // SetCode sets the code for the given address 325 func (d *DeltaView) SetCode(addr gethCommon.Address, code []byte) error { 326 // update code 327 d.codes[addr] = code 328 329 // update code hash 330 codeHash := gethTypes.EmptyCodeHash 331 if len(code) > 0 { 332 codeHash = gethCrypto.Keccak256Hash(code) 333 } 334 d.codeHashes[addr] = codeHash 335 336 // flag the address as dirty 337 d.dirtyAddresses[addr] = struct{}{} 338 return nil 339 } 340 341 // GetState returns the value of the slot of the main state 342 func (d *DeltaView) GetState(sk types.SlotAddress) (gethCommon.Hash, error) { 343 val, found := d.slots[sk] 344 if found { 345 return val, nil 346 } 347 // if address is deleted in the scope of this delta view, 348 // don't go backward. this has been done to skip the step to iterate 349 // over all the state slabs and delete them. 350 _, recreated := d.recreated[sk.Address] 351 if recreated { 352 return gethCommon.Hash{}, nil 353 } 354 return d.parent.GetState(sk) 355 } 356 357 // SetState adds sets a value for the given slot of the main storage 358 func (d *DeltaView) SetState(sk types.SlotAddress, value gethCommon.Hash) error { 359 lastValue, err := d.GetState(sk) 360 if err != nil { 361 return err 362 } 363 // if the value hasn't changed, skip 364 if value == lastValue { 365 return nil 366 } 367 d.slots[sk] = value 368 return nil 369 } 370 371 // GetTransientState returns the value of the slot of the transient state 372 func (d *DeltaView) GetTransientState(sk types.SlotAddress) gethCommon.Hash { 373 if d.transient != nil { 374 val, found := d.transient[sk] 375 if found { 376 return val 377 } 378 } 379 return d.parent.GetTransientState(sk) 380 } 381 382 // SetTransientState adds sets a value for the given slot of the transient storage 383 func (d *DeltaView) SetTransientState(sk types.SlotAddress, value gethCommon.Hash) { 384 if d.transient == nil { 385 d.transient = make(map[types.SlotAddress]gethCommon.Hash) 386 } 387 d.transient[sk] = value 388 } 389 390 // GetRefund returns the total (gas) refund 391 func (d *DeltaView) GetRefund() uint64 { 392 return d.refund 393 } 394 395 // AddRefund adds the amount to the total (gas) refund 396 func (d *DeltaView) AddRefund(amount uint64) error { 397 d.refund += amount 398 return nil 399 } 400 401 // SubRefund subtracts the amount from the total (gas) refund 402 func (d *DeltaView) SubRefund(amount uint64) error { 403 if amount > d.refund { 404 return fmt.Errorf("refund counter below zero (gas: %d > refund: %d)", amount, d.refund) 405 } 406 d.refund -= amount 407 return nil 408 } 409 410 // AddressInAccessList checks if the address is in the access list 411 func (d *DeltaView) AddressInAccessList(addr gethCommon.Address) bool { 412 if d.accessListAddresses != nil { 413 _, addressFound := d.accessListAddresses[addr] 414 if addressFound { 415 return true 416 } 417 } 418 return d.parent.AddressInAccessList(addr) 419 } 420 421 // AddAddressToAccessList adds an address to the access list 422 func (d *DeltaView) AddAddressToAccessList(addr gethCommon.Address) bool { 423 if d.accessListAddresses == nil { 424 d.accessListAddresses = make(map[gethCommon.Address]struct{}) 425 } 426 427 addrPresent := d.AddressInAccessList(addr) 428 d.accessListAddresses[addr] = struct{}{} 429 return !addrPresent 430 } 431 432 // SlotInAccessList checks if the slot is in the access list 433 func (d *DeltaView) SlotInAccessList(sk types.SlotAddress) (addressOk bool, slotOk bool) { 434 addressFound := d.AddressInAccessList(sk.Address) 435 if d.accessListSlots != nil { 436 _, slotFound := d.accessListSlots[sk] 437 if slotFound { 438 return addressFound, true 439 } 440 } 441 _, slotFound := d.parent.SlotInAccessList(sk) 442 return addressFound, slotFound 443 } 444 445 // AddSlotToAccessList adds a slot to the access list 446 // it also adds the address to the address list 447 func (d *DeltaView) AddSlotToAccessList(sk types.SlotAddress) (addrAdded bool, slotAdded bool) { 448 addrPresent, slotPresent := d.SlotInAccessList(sk) 449 if d.accessListAddresses == nil { 450 d.accessListAddresses = make(map[gethCommon.Address]struct{}) 451 } 452 d.accessListAddresses[sk.Address] = struct{}{} 453 if d.accessListSlots == nil { 454 d.accessListSlots = make(map[types.SlotAddress]struct{}) 455 } 456 d.accessListSlots[sk] = struct{}{} 457 return !addrPresent, !slotPresent 458 } 459 460 // AddLog appends a log to the log collection 461 func (d *DeltaView) AddLog(log *gethTypes.Log) { 462 if d.logs == nil { 463 d.logs = make([]*gethTypes.Log, 0) 464 } 465 d.logs = append(d.logs, log) 466 } 467 468 // Logs returns the logs that has been captured in this view 469 func (d *DeltaView) Logs() []*gethTypes.Log { 470 return d.logs 471 } 472 473 // AddPreimage adds a preimage 474 func (d *DeltaView) AddPreimage(hash gethCommon.Hash, preimage []byte) { 475 if d.preimages == nil { 476 d.preimages = make(map[gethCommon.Hash][]byte) 477 } 478 479 // make a copy (legacy behaviour) 480 pi := make([]byte, len(preimage)) 481 copy(pi, preimage) 482 d.preimages[hash] = pi 483 } 484 485 // Preimages returns a map of preimages 486 func (d *DeltaView) Preimages() map[gethCommon.Hash][]byte { 487 return d.preimages 488 } 489 490 // DirtyAddresses returns a set of addresses that has been updated in this view 491 func (d *DeltaView) DirtyAddresses() map[gethCommon.Address]struct{} { 492 return d.dirtyAddresses 493 } 494 495 // DirtySlots returns a set of slots that has been updated in this view 496 func (d *DeltaView) DirtySlots() map[types.SlotAddress]struct{} { 497 dirtySlots := make(map[types.SlotAddress]struct{}) 498 for sk := range d.slots { 499 dirtySlots[sk] = struct{}{} 500 } 501 return dirtySlots 502 }