From 3e4cb3d7df53ba110570eafba29ecd17addccf19 Mon Sep 17 00:00:00 2001 From: lightclient Date: Mon, 23 Jun 2025 12:44:35 +0200 Subject: [PATCH] core: fixups for devnet-2 --- cmd/evm/internal/t8ntool/transaction.go | 2 +- core/state/statedb.go | 4 ++ core/txpool/validation.go | 4 +- core/vm/operations_acl.go | 50 ++++++++++++++++--------- params/protocol_params.go | 10 +++-- 5 files changed, 46 insertions(+), 24 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index 2bc4f73b60..d91f0d88c0 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -180,7 +180,7 @@ func Transaction(ctx *cli.Context) error { r.Error = errors.New("gas * maxFeePerGas exceeds 256 bits") } // Check whether the init code size has been exceeded. - if chainConfig.IsShanghai(new(big.Int), 0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { + if chainConfig.IsShanghai(new(big.Int), 0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSizeEIP3860 { r.Error = errors.New("max initcode size exceeded") } results = append(results, r) diff --git a/core/state/statedb.go b/core/state/statedb.go index 0be1769ca7..1498e12d97 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1361,6 +1361,10 @@ func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, d al.AddAddress(sender) if dst != nil { al.AddAddress(*dst) + // TODO: add for devnet-3 + // if rules.IsOsaka { + // al.AddAddressCode(*dst) + // } // If it's a create-tx, the destination will be added inside evm.create } for _, addr := range precompiles { diff --git a/core/txpool/validation.go b/core/txpool/validation.go index fef1a99f7b..49084de1f2 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -87,8 +87,8 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types return fmt.Errorf("%w: type %d rejected, pool not yet in Prague", core.ErrTxTypeNotSupported, tx.Type()) } // Check whether the init code size has been exceeded - if rules.IsShanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { - return fmt.Errorf("%w: code size %v, limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize) + if rules.IsShanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSizeEIP7907 { + return fmt.Errorf("%w: code size %v, limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSizeEIP7907) } // Transactions can't be negative. This may never happen using RLP decoded // transactions but may occur for transactions created using the RPC. diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index 0bdfa32380..070b651280 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -18,6 +18,7 @@ package vm import ( "errors" + "fmt" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" @@ -318,12 +319,25 @@ var ( gasCallCodeEIP7907 = makeCallVariantGasCallEIP7907(gasCallCode) ) -func getColdCodeAccessGasCost(evm *EVM, addr common.Address) uint64 { - codeSize := evm.StateDB.GetCodeSize(addr) - if codeSize <= params.MaxCodeSizeEIP7907 { +// Rounds n up to the nearest multiple of 32. +func ceil32(n int) uint64 { + r := n % 32 + if r == 0 { + return uint64(n) + } else { + return uint64(n + 32 - r) + } +} + +func calcColdCodeAccessGasCost(evm *EVM, addr common.Address) uint64 { + size := evm.StateDB.GetCodeSize(addr) + // Only charge additional access cost for contracts larger than old limit. + if size <= params.MaxCodeSizeEIP170 { return 0 } - return (uint64(codeSize) - params.MaxCodeSizeEIP7907) * 2 / 32 + excess := ceil32(size - params.MaxCodeSizeEIP170) + fmt.Println("excess", excess, "cost", (excess*params.CodeReadPerWordGasEIP7907)/32) + return (excess * params.CodeReadPerWordGasEIP7907) / 32 } func makeCallVariantGasCallEIP7907(oldCalculator gasFunc) gasFunc { @@ -346,9 +360,10 @@ func makeCallVariantGasCallEIP7907(oldCalculator gasFunc) gasFunc { } total += coldCost } + // Check code presence in the access list if !evm.StateDB.AddressCodeInAccessList(addr) { - cost := getColdCodeAccessGasCost(evm, addr) + cost := calcColdCodeAccessGasCost(evm, addr) evm.StateDB.AddAddressCodeToAccessList(addr) if !contract.UseGas(cost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { return 0, ErrOutOfGas @@ -356,6 +371,9 @@ func makeCallVariantGasCallEIP7907(oldCalculator gasFunc) gasFunc { total += cost } + // TODO: reading code here would defeat the purpose of separate charging, so + // we should first see if the code size is 23 bytes before parsing. + // Check if code is a delegation and if so, charge for resolution. if target, ok := types.ParseDelegation(evm.StateDB.GetCode(addr)); ok { var cost uint64 @@ -370,7 +388,7 @@ func makeCallVariantGasCallEIP7907(oldCalculator gasFunc) gasFunc { } total += cost if !evm.StateDB.AddressCodeInAccessList(target) { - cost = getColdCodeAccessGasCost(evm, target) + cost = calcColdCodeAccessGasCost(evm, target) evm.StateDB.AddAddressCodeToAccessList(target) if !contract.UseGas(cost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { return 0, ErrOutOfGas @@ -410,27 +428,25 @@ func gasExtCodeCopyEIP7907(evm *EVM, contract *Contract, stack *Stack, mem *Memo return 0, err } addr := common.Address(stack.peek().Bytes20()) - var total uint64 // Check slot presence in the access list if !evm.StateDB.AddressInAccessList(addr) { evm.StateDB.AddAddressToAccessList(addr) + var overflow bool // We charge (cold-warm), since 'warm' is already charged as constantGas - - if !contract.UseGas(gas, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { - return 0, ErrOutOfGas + if gas, overflow = math.SafeAdd(gas, params.ColdAccountAccessCostEIP2929-params.WarmStorageReadCostEIP2929); overflow { + return 0, ErrGasUintOverflow } - total += gas } // Check address code presence in the access list if !evm.StateDB.AddressCodeInAccessList(addr) { - cost := getColdCodeAccessGasCost(evm, addr) + cost := calcColdCodeAccessGasCost(evm, addr) evm.StateDB.AddAddressCodeToAccessList(addr) - if !contract.UseGas(cost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { - return 0, ErrOutOfGas + var overflow bool + // We charge (cold-warm), since 'warm' is already charged as constantGas + if gas, overflow = math.SafeAdd(gas, cost); overflow { + return 0, ErrGasUintOverflow } - total += cost } - - return total, nil + return gas, nil } diff --git a/params/protocol_params.go b/params/protocol_params.go index 6b376d4072..408c8801d4 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -132,10 +132,12 @@ const ( DefaultElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have. InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks. - MaxCodeSizeEIP170 = 24576 // Maximum bytecode to permit for a contract - MaxCodeSizeEIP7907 = 268435456 // Maximum bytecode permitted per contract after EIP-7907 - MaxInitCodeSizeEIP3860 = 2 * MaxCodeSizeEIP170 // Maximum initcode to permit in a creation transaction and create instructions - MaxInitCodeSizeEIP7907 = 2 * MaxCodeSizeEIP7907 // Maximum initcode to permit in a creation transaction and create instructions + MaxCodeSizeEIP170 = 24576 // Maximum bytecode to permit for a contract + MaxInitCodeSizeEIP3860 = 2 * MaxCodeSizeEIP170 // Maximum initcode to permit in a creation transaction and create instructions + + MaxCodeSizeEIP7907 = 262144 // Maximum bytecode permitted per contract after EIP-7907 + MaxInitCodeSizeEIP7907 = 2 * MaxCodeSizeEIP7907 // Maximum initcode to permit in a creation transaction and create instructions + CodeReadPerWordGasEIP7907 = 2 // Cost per word to read code from disk. // Precompiled contract gas prices