github.com/phillinzzz/newBsc@v1.1.6/core/vm/access_list_tracer.go (about) 1 // Copyright 2021 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package vm 18 19 import ( 20 "math/big" 21 "time" 22 23 "github.com/phillinzzz/newBsc/common" 24 "github.com/phillinzzz/newBsc/core/types" 25 ) 26 27 // accessList is an accumulator for the set of accounts and storage slots an EVM 28 // contract execution touches. 29 type accessList map[common.Address]accessListSlots 30 31 // accessListSlots is an accumulator for the set of storage slots within a single 32 // contract that an EVM contract execution touches. 33 type accessListSlots map[common.Hash]struct{} 34 35 // newAccessList creates a new accessList. 36 func newAccessList() accessList { 37 return make(map[common.Address]accessListSlots) 38 } 39 40 // addAddress adds an address to the accesslist. 41 func (al accessList) addAddress(address common.Address) { 42 // Set address if not previously present 43 if _, present := al[address]; !present { 44 al[address] = make(map[common.Hash]struct{}) 45 } 46 } 47 48 // addSlot adds a storage slot to the accesslist. 49 func (al accessList) addSlot(address common.Address, slot common.Hash) { 50 // Set address if not previously present 51 al.addAddress(address) 52 53 // Set the slot on the surely existent storage set 54 al[address][slot] = struct{}{} 55 } 56 57 // equal checks if the content of the current access list is the same as the 58 // content of the other one. 59 func (al accessList) equal(other accessList) bool { 60 // Cross reference the accounts first 61 if len(al) != len(other) { 62 return false 63 } 64 for addr := range al { 65 if _, ok := other[addr]; !ok { 66 return false 67 } 68 } 69 for addr := range other { 70 if _, ok := al[addr]; !ok { 71 return false 72 } 73 } 74 // Accounts match, cross reference the storage slots too 75 for addr, slots := range al { 76 otherslots := other[addr] 77 78 if len(slots) != len(otherslots) { 79 return false 80 } 81 for hash := range slots { 82 if _, ok := otherslots[hash]; !ok { 83 return false 84 } 85 } 86 for hash := range otherslots { 87 if _, ok := slots[hash]; !ok { 88 return false 89 } 90 } 91 } 92 return true 93 } 94 95 // accesslist converts the accesslist to a types.AccessList. 96 func (al accessList) accessList() types.AccessList { 97 acl := make(types.AccessList, 0, len(al)) 98 for addr, slots := range al { 99 tuple := types.AccessTuple{Address: addr} 100 for slot := range slots { 101 tuple.StorageKeys = append(tuple.StorageKeys, slot) 102 } 103 acl = append(acl, tuple) 104 } 105 return acl 106 } 107 108 // AccessListTracer is a tracer that accumulates touched accounts and storage 109 // slots into an internal set. 110 type AccessListTracer struct { 111 excl map[common.Address]struct{} // Set of account to exclude from the list 112 list accessList // Set of accounts and storage slots touched 113 } 114 115 // NewAccessListTracer creates a new tracer that can generate AccessLists. 116 // An optional AccessList can be specified to occupy slots and addresses in 117 // the resulting accesslist. 118 func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompiles []common.Address) *AccessListTracer { 119 excl := map[common.Address]struct{}{ 120 from: {}, to: {}, 121 } 122 for _, addr := range precompiles { 123 excl[addr] = struct{}{} 124 } 125 list := newAccessList() 126 for _, al := range acl { 127 if _, ok := excl[al.Address]; !ok { 128 list.addAddress(al.Address) 129 } 130 for _, slot := range al.StorageKeys { 131 list.addSlot(al.Address, slot) 132 } 133 } 134 return &AccessListTracer{ 135 excl: excl, 136 list: list, 137 } 138 } 139 140 func (a *AccessListTracer) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { 141 } 142 143 // CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist. 144 func (a *AccessListTracer) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) { 145 stack := scope.Stack 146 if (op == SLOAD || op == SSTORE) && stack.len() >= 1 { 147 slot := common.Hash(stack.data[stack.len()-1].Bytes32()) 148 a.list.addSlot(scope.Contract.Address(), slot) 149 } 150 if (op == EXTCODECOPY || op == EXTCODEHASH || op == EXTCODESIZE || op == BALANCE || op == SELFDESTRUCT) && stack.len() >= 1 { 151 addr := common.Address(stack.data[stack.len()-1].Bytes20()) 152 if _, ok := a.excl[addr]; !ok { 153 a.list.addAddress(addr) 154 } 155 } 156 if (op == DELEGATECALL || op == CALL || op == STATICCALL || op == CALLCODE) && stack.len() >= 5 { 157 addr := common.Address(stack.data[stack.len()-2].Bytes20()) 158 if _, ok := a.excl[addr]; !ok { 159 a.list.addAddress(addr) 160 } 161 } 162 } 163 164 func (*AccessListTracer) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) { 165 } 166 167 func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {} 168 169 // AccessList returns the current accesslist maintained by the tracer. 170 func (a *AccessListTracer) AccessList() types.AccessList { 171 return a.list.accessList() 172 } 173 174 // Equal returns if the content of two access list traces are equal. 175 func (a *AccessListTracer) Equal(other *AccessListTracer) bool { 176 return a.list.equal(other.list) 177 }