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