access_list.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // Copyright 2020 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package state
  17. import (
  18. "github.com/ethereum/go-ethereum/common"
  19. )
  20. type accessList struct {
  21. addresses map[common.Address]int
  22. slots []map[common.Hash]struct{}
  23. }
  24. // ContainsAddress returns true if the address is in the access list.
  25. func (al *accessList) ContainsAddress(address common.Address) bool {
  26. _, ok := al.addresses[address]
  27. return ok
  28. }
  29. // Contains checks if a slot within an account is present in the access list, returning
  30. // separate flags for the presence of the account and the slot respectively.
  31. func (al *accessList) Contains(address common.Address, slot common.Hash) (addressPresent bool, slotPresent bool) {
  32. idx, ok := al.addresses[address]
  33. if !ok {
  34. // no such address (and hence zero slots)
  35. return false, false
  36. }
  37. if idx == -1 {
  38. // address yes, but no slots
  39. return true, false
  40. }
  41. _, slotPresent = al.slots[idx][slot]
  42. return true, slotPresent
  43. }
  44. // newAccessList creates a new accessList.
  45. func newAccessList() *accessList {
  46. return &accessList{
  47. addresses: make(map[common.Address]int),
  48. }
  49. }
  50. // Copy creates an independent copy of an accessList.
  51. func (a *accessList) Copy() *accessList {
  52. cp := newAccessList()
  53. for k, v := range a.addresses {
  54. cp.addresses[k] = v
  55. }
  56. cp.slots = make([]map[common.Hash]struct{}, len(a.slots))
  57. for i, slotMap := range a.slots {
  58. newSlotmap := make(map[common.Hash]struct{}, len(slotMap))
  59. for k := range slotMap {
  60. newSlotmap[k] = struct{}{}
  61. }
  62. cp.slots[i] = newSlotmap
  63. }
  64. return cp
  65. }
  66. // AddAddress adds an address to the access list, and returns 'true' if the operation
  67. // caused a change (addr was not previously in the list).
  68. func (al *accessList) AddAddress(address common.Address) bool {
  69. if _, present := al.addresses[address]; present {
  70. return false
  71. }
  72. al.addresses[address] = -1
  73. return true
  74. }
  75. // AddSlot adds the specified (addr, slot) combo to the access list.
  76. // Return values are:
  77. // - address added
  78. // - slot added
  79. // For any 'true' value returned, a corresponding journal entry must be made.
  80. func (al *accessList) AddSlot(address common.Address, slot common.Hash) (addrChange bool, slotChange bool) {
  81. idx, addrPresent := al.addresses[address]
  82. if !addrPresent || idx == -1 {
  83. // Address not present, or addr present but no slots there
  84. al.addresses[address] = len(al.slots)
  85. slotmap := map[common.Hash]struct{}{slot: {}}
  86. al.slots = append(al.slots, slotmap)
  87. return !addrPresent, true
  88. }
  89. // There is already an (address,slot) mapping
  90. slotmap := al.slots[idx]
  91. if _, ok := slotmap[slot]; !ok {
  92. slotmap[slot] = struct{}{}
  93. // Journal add slot change
  94. return false, true
  95. }
  96. // No changes required
  97. return false, false
  98. }
  99. // DeleteSlot removes an (address, slot)-tuple from the access list.
  100. // This operation needs to be performed in the same order as the addition happened.
  101. // This method is meant to be used by the journal, which maintains ordering of
  102. // operations.
  103. func (al *accessList) DeleteSlot(address common.Address, slot common.Hash) {
  104. idx, addrOk := al.addresses[address]
  105. // There are two ways this can fail
  106. if !addrOk {
  107. panic("reverting slot change, address not present in list")
  108. }
  109. slotmap := al.slots[idx]
  110. delete(slotmap, slot)
  111. // If that was the last (first) slot, remove it
  112. // Since additions and rollbacks are always performed in order,
  113. // we can delete the item without worrying about screwing up later indices
  114. if len(slotmap) == 0 {
  115. al.slots = al.slots[:idx]
  116. al.addresses[address] = -1
  117. }
  118. }
  119. // DeleteAddress removes an address from the access list. This operation
  120. // needs to be performed in the same order as the addition happened.
  121. // This method is meant to be used by the journal, which maintains ordering of
  122. // operations.
  123. func (al *accessList) DeleteAddress(address common.Address) {
  124. delete(al.addresses, address)
  125. }