github.com/amazechain/amc@v0.1.3/modules/state/access_list.go (about)

     1  // Copyright 2023 The AmazeChain Authors
     2  // This file is part of the AmazeChain library.
     3  //
     4  // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package state
    18  
    19  import (
    20  	"github.com/amazechain/amc/common/types"
    21  )
    22  
    23  type accessList struct {
    24  	addresses map[types.Address]int
    25  	slots     []map[types.Hash]struct{}
    26  }
    27  
    28  // ContainsAddress returns true if the address is in the access list.
    29  func (al *accessList) ContainsAddress(address types.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 types.Address, slot types.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[types.Address]int),
    54  	}
    55  }
    56  
    57  // Copy creates an independent copy of an accessList.
    58  func (al *accessList) Copy() *accessList {
    59  	cp := newAccessList()
    60  	for k, v := range al.addresses {
    61  		cp.addresses[k] = v
    62  	}
    63  	cp.slots = make([]map[types.Hash]struct{}, len(al.slots))
    64  	for i, slotMap := range al.slots {
    65  		newSlotmap := make(map[types.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 types.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 types.Address, slot types.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[types.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 types.Address, slot types.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 types.Address) {
   135  	delete(al.addresses, address)
   136  }