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