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  }