@@ -21,6 +21,7 @@ import (
2121
2222 "github.com/ethereum/go-ethereum/common"
2323 "github.com/ethereum/go-ethereum/common/math"
24+ "github.com/ethereum/go-ethereum/core/types"
2425 "github.com/ethereum/go-ethereum/params"
2526)
2627
@@ -247,3 +248,70 @@ func makeSelfdestructGasFn(refundsEnabled bool) gasFunc {
247248 }
248249 return gasFunc
249250}
251+
252+ var (
253+ gasCallEIP7702 = makeCallVariantGasCallEIP7702 (gasCall )
254+ gasDelegateCallEIP7702 = makeCallVariantGasCallEIP7702 (gasDelegateCall )
255+ gasStaticCallEIP7702 = makeCallVariantGasCallEIP7702 (gasStaticCall )
256+ gasCallCodeEIP7702 = makeCallVariantGasCallEIP7702 (gasCallCode )
257+ )
258+
259+ func makeCallVariantGasCallEIP7702 (oldCalculator gasFunc ) gasFunc {
260+ return func (evm * EVM , contract * Contract , stack * Stack , mem * Memory , memorySize uint64 ) (uint64 , error ) {
261+ var (
262+ total uint64 // total dynamic gas used
263+ addr = common .Address (stack .Back (1 ).Bytes20 ())
264+ )
265+
266+ // Check slot presence in the access list
267+ if ! evm .StateDB .AddressInAccessList (addr ) {
268+ evm .StateDB .AddAddressToAccessList (addr )
269+ // The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so
270+ // the cost to charge for cold access, if any, is Cold - Warm
271+ coldCost := params .ColdAccountAccessCostEIP2929 - params .WarmStorageReadCostEIP2929
272+ // Charge the remaining difference here already, to correctly calculate available
273+ // gas for call
274+ if ! contract .UseGas (coldCost ) {
275+ return 0 , ErrOutOfGas
276+ }
277+ total += coldCost
278+ }
279+
280+ // Check if code is a delegation and if so, charge for resolution.
281+ if target , ok := types .ParseDelegation (evm .StateDB .GetCode (addr )); ok {
282+ var cost uint64
283+ if evm .StateDB .AddressInAccessList (target ) {
284+ cost = params .WarmStorageReadCostEIP2929
285+ } else {
286+ evm .StateDB .AddAddressToAccessList (target )
287+ cost = params .ColdAccountAccessCostEIP2929
288+ }
289+ if ! contract .UseGas (cost ) {
290+ return 0 , ErrOutOfGas
291+ }
292+ total += cost
293+ }
294+
295+ // Now call the old calculator, which takes into account
296+ // - create new account
297+ // - transfer value
298+ // - memory expansion
299+ // - 63/64ths rule
300+ old , err := oldCalculator (evm , contract , stack , mem , memorySize )
301+ if err != nil {
302+ return old , err
303+ }
304+
305+ // Temporarily add the gas charge back to the contract and return value. By
306+ // adding it to the return, it will be charged outside of this function, as
307+ // part of the dynamic gas. This will ensure it is correctly reported to
308+ // tracers.
309+ contract .Gas += total
310+
311+ var overflow bool
312+ if total , overflow = math .SafeAdd (old , total ); overflow {
313+ return 0 , ErrGasUintOverflow
314+ }
315+ return total , nil
316+ }
317+ }
0 commit comments