github.com/ethereum/go-ethereum@v1.16.1/core/vm/operations_verkle.go (about) 1 // Copyright 2024 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 gomath "math" 21 22 "github.com/ethereum/go-ethereum/common" 23 "github.com/ethereum/go-ethereum/common/math" 24 "github.com/ethereum/go-ethereum/params" 25 ) 26 27 func gasSStore4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 28 return evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), true, contract.Gas, true), nil 29 } 30 31 func gasSLoad4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 32 return evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), false, contract.Gas, true), nil 33 } 34 35 func gasBalance4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 36 address := stack.peek().Bytes20() 37 return evm.AccessEvents.BasicDataGas(address, false, contract.Gas, true), nil 38 } 39 40 func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 41 address := stack.peek().Bytes20() 42 if _, isPrecompile := evm.precompile(address); isPrecompile { 43 return 0, nil 44 } 45 return evm.AccessEvents.BasicDataGas(address, false, contract.Gas, true), nil 46 } 47 48 func gasExtCodeHash4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 49 address := stack.peek().Bytes20() 50 if _, isPrecompile := evm.precompile(address); isPrecompile { 51 return 0, nil 52 } 53 return evm.AccessEvents.CodeHashGas(address, false, contract.Gas, true), nil 54 } 55 56 func makeCallVariantGasEIP4762(oldCalculator gasFunc, withTransferCosts bool) gasFunc { 57 return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 58 var ( 59 target = common.Address(stack.Back(1).Bytes20()) 60 witnessGas uint64 61 _, isPrecompile = evm.precompile(target) 62 isSystemContract = target == params.HistoryStorageAddress 63 ) 64 65 // If value is transferred, it is charged before 1/64th 66 // is subtracted from the available gas pool. 67 if withTransferCosts && !stack.Back(2).IsZero() { 68 wantedValueTransferWitnessGas := evm.AccessEvents.ValueTransferGas(contract.Address(), target, contract.Gas) 69 if wantedValueTransferWitnessGas > contract.Gas { 70 return wantedValueTransferWitnessGas, nil 71 } 72 witnessGas = wantedValueTransferWitnessGas 73 } else if isPrecompile || isSystemContract { 74 witnessGas = params.WarmStorageReadCostEIP2929 75 } else { 76 // The charging for the value transfer is done BEFORE subtracting 77 // the 1/64th gas, as this is considered part of the CALL instruction. 78 // (so before we get to this point) 79 // But the message call is part of the subcall, for which only 63/64th 80 // of the gas should be available. 81 wantedMessageCallWitnessGas := evm.AccessEvents.MessageCallGas(target, contract.Gas-witnessGas) 82 var overflow bool 83 if witnessGas, overflow = math.SafeAdd(witnessGas, wantedMessageCallWitnessGas); overflow { 84 return 0, ErrGasUintOverflow 85 } 86 if witnessGas > contract.Gas { 87 return witnessGas, nil 88 } 89 } 90 91 contract.Gas -= witnessGas 92 // if the operation fails, adds witness gas to the gas before returning the error 93 gas, err := oldCalculator(evm, contract, stack, mem, memorySize) 94 contract.Gas += witnessGas // restore witness gas so that it can be charged at the callsite 95 var overflow bool 96 if gas, overflow = math.SafeAdd(gas, witnessGas); overflow { 97 return 0, ErrGasUintOverflow 98 } 99 return gas, err 100 } 101 } 102 103 var ( 104 gasCallEIP4762 = makeCallVariantGasEIP4762(gasCall, true) 105 gasCallCodeEIP4762 = makeCallVariantGasEIP4762(gasCallCode, false) 106 gasStaticCallEIP4762 = makeCallVariantGasEIP4762(gasStaticCall, false) 107 gasDelegateCallEIP4762 = makeCallVariantGasEIP4762(gasDelegateCall, false) 108 ) 109 110 func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 111 beneficiaryAddr := common.Address(stack.peek().Bytes20()) 112 if _, isPrecompile := evm.precompile(beneficiaryAddr); isPrecompile { 113 return 0, nil 114 } 115 if contract.IsSystemCall { 116 return 0, nil 117 } 118 contractAddr := contract.Address() 119 wanted := evm.AccessEvents.BasicDataGas(contractAddr, false, contract.Gas, false) 120 if wanted > contract.Gas { 121 return wanted, nil 122 } 123 statelessGas := wanted 124 balanceIsZero := evm.StateDB.GetBalance(contractAddr).Sign() == 0 125 _, isPrecompile := evm.precompile(beneficiaryAddr) 126 isSystemContract := beneficiaryAddr == params.HistoryStorageAddress 127 128 if (isPrecompile || isSystemContract) && balanceIsZero { 129 return statelessGas, nil 130 } 131 132 if contractAddr != beneficiaryAddr { 133 wanted := evm.AccessEvents.BasicDataGas(beneficiaryAddr, false, contract.Gas-statelessGas, false) 134 if wanted > contract.Gas-statelessGas { 135 return statelessGas + wanted, nil 136 } 137 statelessGas += wanted 138 } 139 // Charge write costs if it transfers value 140 if !balanceIsZero { 141 wanted := evm.AccessEvents.BasicDataGas(contractAddr, true, contract.Gas-statelessGas, false) 142 if wanted > contract.Gas-statelessGas { 143 return statelessGas + wanted, nil 144 } 145 statelessGas += wanted 146 147 if contractAddr != beneficiaryAddr { 148 if evm.StateDB.Exist(beneficiaryAddr) { 149 wanted = evm.AccessEvents.BasicDataGas(beneficiaryAddr, true, contract.Gas-statelessGas, false) 150 } else { 151 wanted = evm.AccessEvents.AddAccount(beneficiaryAddr, true, contract.Gas-statelessGas) 152 } 153 if wanted > contract.Gas-statelessGas { 154 return statelessGas + wanted, nil 155 } 156 statelessGas += wanted 157 } 158 } 159 return statelessGas, nil 160 } 161 162 func gasCodeCopyEip4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 163 gas, err := gasCodeCopy(evm, contract, stack, mem, memorySize) 164 if err != nil { 165 return 0, err 166 } 167 if !contract.IsDeployment && !contract.IsSystemCall { 168 var ( 169 codeOffset = stack.Back(1) 170 length = stack.Back(2) 171 ) 172 uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow() 173 if overflow { 174 uint64CodeOffset = gomath.MaxUint64 175 } 176 177 _, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(contract.Code, uint64CodeOffset, length.Uint64()) 178 _, wanted := evm.AccessEvents.CodeChunksRangeGas(contract.Address(), copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false, contract.Gas-gas) 179 gas += wanted 180 } 181 return gas, nil 182 } 183 184 func gasExtCodeCopyEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 185 // memory expansion first (dynamic part of pre-2929 implementation) 186 gas, err := gasExtCodeCopy(evm, contract, stack, mem, memorySize) 187 if err != nil { 188 return 0, err 189 } 190 addr := common.Address(stack.peek().Bytes20()) 191 _, isPrecompile := evm.precompile(addr) 192 if isPrecompile || addr == params.HistoryStorageAddress { 193 var overflow bool 194 if gas, overflow = math.SafeAdd(gas, params.WarmStorageReadCostEIP2929); overflow { 195 return 0, ErrGasUintOverflow 196 } 197 return gas, nil 198 } 199 wgas := evm.AccessEvents.BasicDataGas(addr, false, contract.Gas-gas, true) 200 var overflow bool 201 if gas, overflow = math.SafeAdd(gas, wgas); overflow { 202 return 0, ErrGasUintOverflow 203 } 204 return gas, nil 205 }