137 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			137 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|   | // 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) | ||
|  | } |