github.com/phillinzzz/newBsc@v1.1.6/core/vm/operations_acl.go (about) 1 // Copyright 2020 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 "errors" 21 22 "github.com/phillinzzz/newBsc/common" 23 "github.com/phillinzzz/newBsc/common/math" 24 "github.com/phillinzzz/newBsc/params" 25 ) 26 27 const ( 28 ColdAccountAccessCostEIP2929 = uint64(2600) // COLD_ACCOUNT_ACCESS_COST 29 ColdSloadCostEIP2929 = uint64(2100) // COLD_SLOAD_COST 30 WarmStorageReadCostEIP2929 = uint64(100) // WARM_STORAGE_READ_COST 31 ) 32 33 // gasSStoreEIP2929 implements gas cost for SSTORE according to EIP-2929 34 // 35 // When calling SSTORE, check if the (address, storage_key) pair is in accessed_storage_keys. 36 // If it is not, charge an additional COLD_SLOAD_COST gas, and add the pair to accessed_storage_keys. 37 // Additionally, modify the parameters defined in EIP 2200 as follows: 38 // 39 // Parameter Old value New value 40 // SLOAD_GAS 800 = WARM_STORAGE_READ_COST 41 // SSTORE_RESET_GAS 5000 5000 - COLD_SLOAD_COST 42 // 43 //The other parameters defined in EIP 2200 are unchanged. 44 // see gasSStoreEIP2200(...) in core/vm/gas_table.go for more info about how EIP 2200 is specified 45 func gasSStoreEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 46 // If we fail the minimum gas availability invariant, fail (0) 47 if contract.Gas <= params.SstoreSentryGasEIP2200 { 48 return 0, errors.New("not enough gas for reentrancy sentry") 49 } 50 // Gas sentry honoured, do the actual gas calculation based on the stored value 51 var ( 52 y, x = stack.Back(1), stack.peek() 53 slot = common.Hash(x.Bytes32()) 54 current = evm.StateDB.GetState(contract.Address(), slot) 55 cost = uint64(0) 56 ) 57 // Check slot presence in the access list 58 if addrPresent, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent { 59 cost = ColdSloadCostEIP2929 60 // If the caller cannot afford the cost, this change will be rolled back 61 evm.StateDB.AddSlotToAccessList(contract.Address(), slot) 62 if !addrPresent { 63 // Once we're done with YOLOv2 and schedule this for mainnet, might 64 // be good to remove this panic here, which is just really a 65 // canary to have during testing 66 panic("impossible case: address was not present in access list during sstore op") 67 } 68 } 69 value := common.Hash(y.Bytes32()) 70 71 if current == value { // noop (1) 72 // EIP 2200 original clause: 73 // return params.SloadGasEIP2200, nil 74 return cost + WarmStorageReadCostEIP2929, nil // SLOAD_GAS 75 } 76 original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32()) 77 if original == current { 78 if original == (common.Hash{}) { // create slot (2.1.1) 79 return cost + params.SstoreSetGasEIP2200, nil 80 } 81 if value == (common.Hash{}) { // delete slot (2.1.2b) 82 evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP2200) 83 } 84 // EIP-2200 original clause: 85 // return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2) 86 return cost + (params.SstoreResetGasEIP2200 - ColdSloadCostEIP2929), nil // write existing slot (2.1.2) 87 } 88 if original != (common.Hash{}) { 89 if current == (common.Hash{}) { // recreate slot (2.2.1.1) 90 evm.StateDB.SubRefund(params.SstoreClearsScheduleRefundEIP2200) 91 } else if value == (common.Hash{}) { // delete slot (2.2.1.2) 92 evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP2200) 93 } 94 } 95 if original == value { 96 if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1) 97 // EIP 2200 Original clause: 98 //evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200) 99 evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - WarmStorageReadCostEIP2929) 100 } else { // reset to original existing slot (2.2.2.2) 101 // EIP 2200 Original clause: 102 // evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200) 103 // - SSTORE_RESET_GAS redefined as (5000 - COLD_SLOAD_COST) 104 // - SLOAD_GAS redefined as WARM_STORAGE_READ_COST 105 // Final: (5000 - COLD_SLOAD_COST) - WARM_STORAGE_READ_COST 106 evm.StateDB.AddRefund((params.SstoreResetGasEIP2200 - ColdSloadCostEIP2929) - WarmStorageReadCostEIP2929) 107 } 108 } 109 // EIP-2200 original clause: 110 //return params.SloadGasEIP2200, nil // dirty update (2.2) 111 return cost + WarmStorageReadCostEIP2929, nil // dirty update (2.2) 112 } 113 114 // gasSLoadEIP2929 calculates dynamic gas for SLOAD according to EIP-2929 115 // For SLOAD, if the (address, storage_key) pair (where address is the address of the contract 116 // whose storage is being read) is not yet in accessed_storage_keys, 117 // charge 2100 gas and add the pair to accessed_storage_keys. 118 // If the pair is already in accessed_storage_keys, charge 100 gas. 119 func gasSLoadEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 120 loc := stack.peek() 121 slot := common.Hash(loc.Bytes32()) 122 // Check slot presence in the access list 123 if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent { 124 // If the caller cannot afford the cost, this change will be rolled back 125 // If he does afford it, we can skip checking the same thing later on, during execution 126 evm.StateDB.AddSlotToAccessList(contract.Address(), slot) 127 return ColdSloadCostEIP2929, nil 128 } 129 return WarmStorageReadCostEIP2929, nil 130 } 131 132 // gasExtCodeCopyEIP2929 implements extcodecopy according to EIP-2929 133 // EIP spec: 134 // > If the target is not in accessed_addresses, 135 // > charge COLD_ACCOUNT_ACCESS_COST gas, and add the address to accessed_addresses. 136 // > Otherwise, charge WARM_STORAGE_READ_COST gas. 137 func gasExtCodeCopyEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 138 // memory expansion first (dynamic part of pre-2929 implementation) 139 gas, err := gasExtCodeCopy(evm, contract, stack, mem, memorySize) 140 if err != nil { 141 return 0, err 142 } 143 addr := common.Address(stack.peek().Bytes20()) 144 // Check slot presence in the access list 145 if !evm.StateDB.AddressInAccessList(addr) { 146 evm.StateDB.AddAddressToAccessList(addr) 147 var overflow bool 148 // We charge (cold-warm), since 'warm' is already charged as constantGas 149 if gas, overflow = math.SafeAdd(gas, ColdAccountAccessCostEIP2929-WarmStorageReadCostEIP2929); overflow { 150 return 0, ErrGasUintOverflow 151 } 152 return gas, nil 153 } 154 return gas, nil 155 } 156 157 // gasEip2929AccountCheck checks whether the first stack item (as address) is present in the access list. 158 // If it is, this method returns '0', otherwise 'cold-warm' gas, presuming that the opcode using it 159 // is also using 'warm' as constant factor. 160 // This method is used by: 161 // - extcodehash, 162 // - extcodesize, 163 // - (ext) balance 164 func gasEip2929AccountCheck(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 165 addr := common.Address(stack.peek().Bytes20()) 166 // Check slot presence in the access list 167 if !evm.StateDB.AddressInAccessList(addr) { 168 // If the caller cannot afford the cost, this change will be rolled back 169 evm.StateDB.AddAddressToAccessList(addr) 170 // The warm storage read cost is already charged as constantGas 171 return ColdAccountAccessCostEIP2929 - WarmStorageReadCostEIP2929, nil 172 } 173 return 0, nil 174 } 175 176 func makeCallVariantGasCallEIP2929(oldCalculator gasFunc) gasFunc { 177 return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 178 addr := common.Address(stack.Back(1).Bytes20()) 179 // Check slot presence in the access list 180 warmAccess := evm.StateDB.AddressInAccessList(addr) 181 // The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so 182 // the cost to charge for cold access, if any, is Cold - Warm 183 coldCost := ColdAccountAccessCostEIP2929 - WarmStorageReadCostEIP2929 184 if !warmAccess { 185 evm.StateDB.AddAddressToAccessList(addr) 186 // Charge the remaining difference here already, to correctly calculate available 187 // gas for call 188 if !contract.UseGas(coldCost) { 189 return 0, ErrOutOfGas 190 } 191 } 192 // Now call the old calculator, which takes into account 193 // - create new account 194 // - transfer value 195 // - memory expansion 196 // - 63/64ths rule 197 gas, err := oldCalculator(evm, contract, stack, mem, memorySize) 198 if warmAccess || err != nil { 199 return gas, err 200 } 201 // In case of a cold access, we temporarily add the cold charge back, and also 202 // add it to the returned gas. By adding it to the return, it will be charged 203 // outside of this function, as part of the dynamic gas, and that will make it 204 // also become correctly reported to tracers. 205 contract.Gas += coldCost 206 return gas + coldCost, nil 207 } 208 } 209 210 var ( 211 gasCallEIP2929 = makeCallVariantGasCallEIP2929(gasCall) 212 gasDelegateCallEIP2929 = makeCallVariantGasCallEIP2929(gasDelegateCall) 213 gasStaticCallEIP2929 = makeCallVariantGasCallEIP2929(gasStaticCall) 214 gasCallCodeEIP2929 = makeCallVariantGasCallEIP2929(gasCallCode) 215 ) 216 217 func gasSelfdestructEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 218 var ( 219 gas uint64 220 address = common.Address(stack.peek().Bytes20()) 221 ) 222 if !evm.StateDB.AddressInAccessList(address) { 223 // If the caller cannot afford the cost, this change will be rolled back 224 evm.StateDB.AddAddressToAccessList(address) 225 gas = ColdAccountAccessCostEIP2929 226 } 227 // if empty and transfers value 228 if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { 229 gas += params.CreateBySelfdestructGas 230 } 231 if !evm.StateDB.HasSuicided(contract.Address()) { 232 evm.StateDB.AddRefund(params.SelfdestructRefundGas) 233 } 234 return gas, nil 235 236 }