github.com/tirogen/go-ethereum@v1.10.12-0.20221226051715-250cfede41b6/core/state/access_list.go (about) 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 17 package state 18 19 import ( 20 "github.com/tirogen/go-ethereum/common" 21 ) 22 23 type accessList struct { 24 addresses map[common.Address]int 25 slots []map[common.Hash]struct{} 26 } 27 28 // ContainsAddress returns true if the address is in the access list. 29 func (al *accessList) ContainsAddress(address common.Address) bool { 30 _, ok := al.addresses[address] 31 return ok 32 } 33 34 // Contains checks if a slot within an account is present in the access list, returning 35 // separate flags for the presence of the account and the slot respectively. 36 func (al *accessList) Contains(address common.Address, slot common.Hash) (addressPresent bool, slotPresent bool) { 37 idx, ok := al.addresses[address] 38 if !ok { 39 // no such address (and hence zero slots) 40 return false, false 41 } 42 if idx == -1 { 43 // address yes, but no slots 44 return true, false 45 } 46 _, slotPresent = al.slots[idx][slot] 47 return true, slotPresent 48 } 49 50 // newAccessList creates a new accessList. 51 func newAccessList() *accessList { 52 return &accessList{ 53 addresses: make(map[common.Address]int), 54 } 55 } 56 57 // Copy creates an independent copy of an accessList. 58 func (a *accessList) Copy() *accessList { 59 cp := newAccessList() 60 for k, v := range a.addresses { 61 cp.addresses[k] = v 62 } 63 cp.slots = make([]map[common.Hash]struct{}, len(a.slots)) 64 for i, slotMap := range a.slots { 65 newSlotmap := make(map[common.Hash]struct{}, len(slotMap)) 66 for k := range slotMap { 67 newSlotmap[k] = struct{}{} 68 } 69 cp.slots[i] = newSlotmap 70 } 71 return cp 72 } 73 74 // AddAddress adds an address to the access list, and returns 'true' if the operation 75 // caused a change (addr was not previously in the list). 76 func (al *accessList) AddAddress(address common.Address) bool { 77 if _, present := al.addresses[address]; present { 78 return false 79 } 80 al.addresses[address] = -1 81 return true 82 } 83 84 // AddSlot adds the specified (addr, slot) combo to the access list. 85 // Return values are: 86 // - address added 87 // - slot added 88 // For any 'true' value returned, a corresponding journal entry must be made. 89 func (al *accessList) AddSlot(address common.Address, slot common.Hash) (addrChange bool, slotChange bool) { 90 idx, addrPresent := al.addresses[address] 91 if !addrPresent || idx == -1 { 92 // Address not present, or addr present but no slots there 93 al.addresses[address] = len(al.slots) 94 slotmap := map[common.Hash]struct{}{slot: {}} 95 al.slots = append(al.slots, slotmap) 96 return !addrPresent, true 97 } 98 // There is already an (address,slot) mapping 99 slotmap := al.slots[idx] 100 if _, ok := slotmap[slot]; !ok { 101 slotmap[slot] = struct{}{} 102 // Journal add slot change 103 return false, true 104 } 105 // No changes required 106 return false, false 107 } 108 109 // DeleteSlot removes an (address, slot)-tuple from the access list. 110 // This operation needs to be performed in the same order as the addition happened. 111 // This method is meant to be used by the journal, which maintains ordering of 112 // operations. 113 func (al *accessList) DeleteSlot(address common.Address, slot common.Hash) { 114 idx, addrOk := al.addresses[address] 115 // There are two ways this can fail 116 if !addrOk { 117 panic("reverting slot change, address not present in list") 118 } 119 slotmap := al.slots[idx] 120 delete(slotmap, slot) 121 // If that was the last (first) slot, remove it 122 // Since additions and rollbacks are always performed in order, 123 // we can delete the item without worrying about screwing up later indices 124 if len(slotmap) == 0 { 125 al.slots = al.slots[:idx] 126 al.addresses[address] = -1 127 } 128 } 129 130 // DeleteAddress removes an address from the access list. This operation 131 // needs to be performed in the same order as the addition happened. 132 // This method is meant to be used by the journal, which maintains ordering of 133 // operations. 134 func (al *accessList) DeleteAddress(address common.Address) { 135 delete(al.addresses, address) 136 }