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  }