123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- // Copyright 2020 The go-ethereum Authors
- // This file is part of the go-ethereum library.
- //
- // The go-ethereum library is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Lesser General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // The go-ethereum library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Lesser General Public License for more details.
- //
- // You should have received a copy of the GNU Lesser General Public License
- // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
- package state
- import (
- "github.com/ethereum/go-ethereum/common"
- )
- type accessList struct {
- addresses map[common.Address]int
- slots []map[common.Hash]struct{}
- }
- // ContainsAddress returns true if the address is in the access list.
- func (al *accessList) ContainsAddress(address common.Address) bool {
- _, ok := al.addresses[address]
- return ok
- }
- // Contains checks if a slot within an account is present in the access list, returning
- // separate flags for the presence of the account and the slot respectively.
- func (al *accessList) Contains(address common.Address, slot common.Hash) (addressPresent bool, slotPresent bool) {
- idx, ok := al.addresses[address]
- if !ok {
- // no such address (and hence zero slots)
- return false, false
- }
- if idx == -1 {
- // address yes, but no slots
- return true, false
- }
- _, slotPresent = al.slots[idx][slot]
- return true, slotPresent
- }
- // newAccessList creates a new accessList.
- func newAccessList() *accessList {
- return &accessList{
- addresses: make(map[common.Address]int),
- }
- }
- // Copy creates an independent copy of an accessList.
- func (a *accessList) Copy() *accessList {
- cp := newAccessList()
- for k, v := range a.addresses {
- cp.addresses[k] = v
- }
- cp.slots = make([]map[common.Hash]struct{}, len(a.slots))
- for i, slotMap := range a.slots {
- newSlotmap := make(map[common.Hash]struct{}, len(slotMap))
- for k := range slotMap {
- newSlotmap[k] = struct{}{}
- }
- cp.slots[i] = newSlotmap
- }
- return cp
- }
- // AddAddress adds an address to the access list, and returns 'true' if the operation
- // caused a change (addr was not previously in the list).
- func (al *accessList) AddAddress(address common.Address) bool {
- if _, present := al.addresses[address]; present {
- return false
- }
- al.addresses[address] = -1
- return true
- }
- // AddSlot adds the specified (addr, slot) combo to the access list.
- // Return values are:
- // - address added
- // - slot added
- // For any 'true' value returned, a corresponding journal entry must be made.
- func (al *accessList) AddSlot(address common.Address, slot common.Hash) (addrChange bool, slotChange bool) {
- idx, addrPresent := al.addresses[address]
- if !addrPresent || idx == -1 {
- // Address not present, or addr present but no slots there
- al.addresses[address] = len(al.slots)
- slotmap := map[common.Hash]struct{}{slot: {}}
- al.slots = append(al.slots, slotmap)
- return !addrPresent, true
- }
- // There is already an (address,slot) mapping
- slotmap := al.slots[idx]
- if _, ok := slotmap[slot]; !ok {
- slotmap[slot] = struct{}{}
- // Journal add slot change
- return false, true
- }
- // No changes required
- return false, false
- }
- // DeleteSlot removes an (address, slot)-tuple from the access list.
- // This operation needs to be performed in the same order as the addition happened.
- // This method is meant to be used by the journal, which maintains ordering of
- // operations.
- func (al *accessList) DeleteSlot(address common.Address, slot common.Hash) {
- idx, addrOk := al.addresses[address]
- // There are two ways this can fail
- if !addrOk {
- panic("reverting slot change, address not present in list")
- }
- slotmap := al.slots[idx]
- delete(slotmap, slot)
- // If that was the last (first) slot, remove it
- // Since additions and rollbacks are always performed in order,
- // we can delete the item without worrying about screwing up later indices
- if len(slotmap) == 0 {
- al.slots = al.slots[:idx]
- al.addresses[address] = -1
- }
- }
- // DeleteAddress removes an address from the access list. This operation
- // needs to be performed in the same order as the addition happened.
- // This method is meant to be used by the journal, which maintains ordering of
- // operations.
- func (al *accessList) DeleteAddress(address common.Address) {
- delete(al.addresses, address)
- }
|