From 58d47483519efc6202baae15235a187b4206fe97 Mon Sep 17 00:00:00 2001 From: chirag-parmar Date: Wed, 11 Jun 2025 17:46:04 +0530 Subject: [PATCH 1/7] eip7907 --- execution_chain/constants.nim | 9 +++++---- execution_chain/core/validate.nim | 2 +- execution_chain/db/access_list.nim | 20 ++++++++++++++++++- execution_chain/db/ledger.nim | 3 +++ execution_chain/evm/computation.nim | 6 +++--- .../evm/interpreter/op_handlers/oph_call.nim | 19 +++++++++++++++++- .../interpreter/op_handlers/oph_create.nim | 4 ++-- .../withdrawals/wd_max_init_code_spec.nim | 2 +- 8 files changed, 52 insertions(+), 13 deletions(-) diff --git a/execution_chain/constants.nim b/execution_chain/constants.nim index 8854f5ead5..8ca1ad3782 100644 --- a/execution_chain/constants.nim +++ b/execution_chain/constants.nim @@ -59,14 +59,15 @@ const ## Fork specific constants - # See EIP-170 (https://eips.ethereum.org/EIPS/eip-170). Maximum code size + # See EIP-7907 (https://eips.ethereum.org/EIPS/eip-7907) Maximum code size # that can be stored for a new contract. Init code when creating a new # contract is not subject to this limit. - EIP170_MAX_CODE_SIZE* = 0x6000 + CODE_SIZE_THRESHOLD* = 0x6000 + EIP7907_MAX_CODE_SIZE* = 0x40000 - # See EIP-3860 (https://eips.ethereum.org/EIPS/eip-3860). Maximum initcode + # See EIP-7907 (https://eips.ethereum.org/EIPS/eip-7907). Maximum initcode # size when creating a new contract. - EIP3860_MAX_INITCODE_SIZE* = 2 * EIP170_MAX_CODE_SIZE + EIP7907_MAX_INITCODE_SIZE* = 0x80000 # 2 * EIP7907_MAX_CODE_SIZE # EIP MaxPrecompilesAddr* = 0xFFFF diff --git a/execution_chain/core/validate.nim b/execution_chain/core/validate.nim index a30e8b7422..8f1dc79656 100644 --- a/execution_chain/core/validate.nim +++ b/execution_chain/core/validate.nim @@ -228,7 +228,7 @@ func validateTxBasic*( if tx.txType == TxEip7702 and fork < FkPrague: return err("invalid tx: Eip7702 Tx type detected before Prague") - if fork >= FkShanghai and tx.contractCreation and tx.payload.len > EIP3860_MAX_INITCODE_SIZE: + if fork >= FkShanghai and tx.contractCreation and tx.payload.len > EIP7907_MAX_INITCODE_SIZE: return err("invalid tx: initcode size exceeds maximum") # The total must be the larger of the two diff --git a/execution_chain/db/access_list.nim b/execution_chain/db/access_list.nim index 0f14e42873..ae1fc791b7 100644 --- a/execution_chain/db/access_list.nim +++ b/execution_chain/db/access_list.nim @@ -21,6 +21,7 @@ type AccessList* = object slots: Table[Address, SlotSet] + codeHashes: seq[Hash32] # ------------------------------------------------------------------------------ # Private helpers @@ -36,6 +37,7 @@ func toStorageKeys(slots: SlotSet): seq[Bytes32] = proc init*(ac: var AccessList) = ac.slots = Table[Address, SlotSet]() + ac.codeHashes = newSeq[Hash32]() proc init*(_: type AccessList): AccessList {.inline.} = result.init() @@ -44,9 +46,12 @@ proc init*(_: type AccessList): AccessList {.inline.} = # Public functions # ------------------------------------------------------------------------------ -func contains*(ac: AccessList, address: Address): bool {.inline.} = +func contains*(ac: accesslist, address: address): bool {.inline.} = address in ac.slots +func contains*(ac: accesslist, codeHash: Hash32): bool {.inline.} = + codeHash in ac.codeHashes + # returnValue: (addressPresent, slotPresent) func contains*(ac: var AccessList, address: Address, slot: UInt256): bool = ac.slots.withValue(address, val): @@ -55,6 +60,7 @@ func contains*(ac: var AccessList, address: Address, slot: UInt256): bool = proc mergeAndReset*(ac, other: var AccessList) = # move values in `other` to `ac` ac.slots.mergeAndReset(other.slots) + ac.codeHashes.mergeAndReset(other.codeHashes) proc add*(ac: var AccessList, address: Address) = if address notin ac.slots: @@ -66,9 +72,17 @@ proc add*(ac: var AccessList, address: Address, slot: UInt256) = do: ac.slots[address] = toHashSet([slot]) +proc add*(ac: var AccessList, codeHash: Hash32) = + if codeHash not in ac.codeHashes: + ac.codeHashes.add(codeHash) + proc clear*(ac: var AccessList) {.inline.} = ac.slots.clear() + ac.codeHashes.setLen(0) +# TODO: accesses code is still not a part of the transaction access list +# but when it does trickle down into the transaction we will have to add +# it here func getAccessList*(ac: AccessList): transactions.AccessList = for address, slots in ac.slots: result.add transactions.AccessPair( @@ -91,4 +105,8 @@ func equal*(ac: AccessList, other: var AccessList): bool = do: return false + for codeHash in ac.codeHashes: + if codeHash not in other: + return false + true diff --git a/execution_chain/db/ledger.nim b/execution_chain/db/ledger.nim index a97c8bd3fd..087496b547 100644 --- a/execution_chain/db/ledger.nim +++ b/execution_chain/db/ledger.nim @@ -829,6 +829,9 @@ proc accessList*(ac: LedgerRef, address: Address) = proc accessList*(ac: LedgerRef, address: Address, slot: UInt256) = ac.savePoint.accessList.add(address, slot) +proc accessList*(ac: LedgerRef, codeHash: Hash32) = + ac.savePoint.accessList.add(address, codeHash) + func inAccessList*(ac: LedgerRef, address: Address): bool = var sp = ac.savePoint while sp != nil: diff --git a/execution_chain/evm/computation.nim b/execution_chain/evm/computation.nim index c4f60e4ef4..94c2130ab7 100644 --- a/execution_chain/evm/computation.nim +++ b/execution_chain/evm/computation.nim @@ -206,9 +206,9 @@ proc writeContract*(c: Computation) = return # EIP-170 constraint (https://eips.ethereum.org/EIPS/eip-3541). - if fork >= FkSpurious and len > EIP170_MAX_CODE_SIZE: - withExtra trace, "New contract code exceeds EIP-170 limit", - codeSize=len, maxSize=EIP170_MAX_CODE_SIZE + if fork >= FkSpurious and len > EIP7907_MAX_CODE_SIZE: + withExtra trace, "New contract code exceeds EIP-7907 limit", + codeSize=len, maxSize=EIP7907_MAX_CODE_SIZE c.setError(StatusCode.OutOfGas, true) return diff --git a/execution_chain/evm/interpreter/op_handlers/oph_call.nim b/execution_chain/evm/interpreter/op_handlers/oph_call.nim index 6f36fbd20b..cefc26f954 100644 --- a/execution_chain/evm/interpreter/op_handlers/oph_call.nim +++ b/execution_chain/evm/interpreter/op_handlers/oph_call.nim @@ -66,6 +66,19 @@ proc gasCallEIP2929(c: Computation, address: Address): GasInt = # the form of a constant `gasCall` return ColdAccountAccessCost - WarmStorageReadCost +proc gasCallEIP7907(c: Computation, codeAddress: Address): GasInt = + c.vmState.mutateLedger: + let codeHash = db.getCodeHash(codeAddress) + + if not db.inAccessList(codeHash): + db.accessList(codeHash) + + let + code = db.getCode(codeAddress) + excessContractSize = max(0, code.len - CODE_SIZE_THRESHOLD) + largeContractCost = (ceil32(excessContractSize) * 2) div 32 + return largeContractCost + proc updateStackAndParams(q: var LocalParams; c: Computation) = c.stack.lsTop(0) @@ -81,11 +94,15 @@ proc updateStackAndParams(q: var LocalParams; c: Computation) = q.memOffset = q.memOutPos q.memLength = q.memOutLen + # EIP7907 + if FkOsaka <= c.fork: + q.gasCallEIPs = gasCallEIP7907(c, q.codeAddress) + # EIP2929: This came before old gas calculator # because it will affect `c.gasMeter.gasRemaining` # and further `childGasLimit` if FkBerlin <= c.fork: - q.gasCallEIPs = gasCallEIP2929(c, q.codeAddress) + q.gasCallEIPs += gasCallEIP2929(c, q.codeAddress) if FkPrague <= c.fork: let delegateTo = parseDelegationAddress(c.getCode(q.codeAddress)) diff --git a/execution_chain/evm/interpreter/op_handlers/oph_create.nim b/execution_chain/evm/interpreter/op_handlers/oph_create.nim index d021cb9827..5b83a8fa03 100644 --- a/execution_chain/evm/interpreter/op_handlers/oph_create.nim +++ b/execution_chain/evm/interpreter/op_handlers/oph_create.nim @@ -77,7 +77,7 @@ proc createOp(cpt: VmCpt): EvmResultVoid = cpt.stack.lsTop(0) # EIP-3860 - if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: + if cpt.fork >= FkShanghai and memLen > EIP7907_MAX_INITCODE_SIZE: trace "Initcode size exceeds maximum", initcodeSize = memLen return err(opErr(InvalidInitCode)) @@ -147,7 +147,7 @@ proc create2Op(cpt: VmCpt): EvmResultVoid = cpt.stack.lsTop(0) # EIP-3860 - if cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: + if cpt.fork >= FkShanghai and memLen > EIP7907_MAX_INITCODE_SIZE: trace "Initcode size exceeds maximum", initcodeSize = memLen return err(opErr(InvalidInitCode)) diff --git a/hive_integration/nodocker/engine/withdrawals/wd_max_init_code_spec.nim b/hive_integration/nodocker/engine/withdrawals/wd_max_init_code_spec.nim index e9bbf1d5af..fa10039077 100644 --- a/hive_integration/nodocker/engine/withdrawals/wd_max_init_code_spec.nim +++ b/hive_integration/nodocker/engine/withdrawals/wd_max_init_code_spec.nim @@ -32,7 +32,7 @@ type overflowMaxInitcodeTxCountAfterFork *: uint64 const - MAX_INITCODE_SIZE = EIP3860_MAX_INITCODE_SIZE + MAX_INITCODE_SIZE = EIP7907_MAX_INITCODE_SIZE proc execute*(ws: MaxInitcodeSizeSpec, env: TestEnv): bool = testCond waitFor env.clMock.waitForTTD() From 72a76c43df3157f9ba585f5573585f2dbdf3cd16 Mon Sep 17 00:00:00 2001 From: chirag-parmar Date: Wed, 11 Jun 2025 18:34:04 +0530 Subject: [PATCH 2/7] fix --- execution_chain/db/access_list.nim | 8 ++++---- execution_chain/db/ledger.nim | 10 +++++++++- .../evm/interpreter/op_handlers/oph_call.nim | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/execution_chain/db/access_list.nim b/execution_chain/db/access_list.nim index ae1fc791b7..b3662a8f16 100644 --- a/execution_chain/db/access_list.nim +++ b/execution_chain/db/access_list.nim @@ -46,10 +46,10 @@ proc init*(_: type AccessList): AccessList {.inline.} = # Public functions # ------------------------------------------------------------------------------ -func contains*(ac: accesslist, address: address): bool {.inline.} = +func contains*(ac: AccessList, address: Address): bool {.inline.} = address in ac.slots -func contains*(ac: accesslist, codeHash: Hash32): bool {.inline.} = +func contains*(ac: AccessList, codeHash: Hash32): bool {.inline.} = codeHash in ac.codeHashes # returnValue: (addressPresent, slotPresent) @@ -73,7 +73,7 @@ proc add*(ac: var AccessList, address: Address, slot: UInt256) = ac.slots[address] = toHashSet([slot]) proc add*(ac: var AccessList, codeHash: Hash32) = - if codeHash not in ac.codeHashes: + if codeHash notin ac.codeHashes: ac.codeHashes.add(codeHash) proc clear*(ac: var AccessList) {.inline.} = @@ -106,7 +106,7 @@ func equal*(ac: AccessList, other: var AccessList): bool = return false for codeHash in ac.codeHashes: - if codeHash not in other: + if codeHash notin other: return false true diff --git a/execution_chain/db/ledger.nim b/execution_chain/db/ledger.nim index 087496b547..5d0d75a33c 100644 --- a/execution_chain/db/ledger.nim +++ b/execution_chain/db/ledger.nim @@ -830,7 +830,7 @@ proc accessList*(ac: LedgerRef, address: Address, slot: UInt256) = ac.savePoint.accessList.add(address, slot) proc accessList*(ac: LedgerRef, codeHash: Hash32) = - ac.savePoint.accessList.add(address, codeHash) + ac.savePoint.accessList.add(codeHash) func inAccessList*(ac: LedgerRef, address: Address): bool = var sp = ac.savePoint @@ -848,6 +848,14 @@ func inAccessList*(ac: LedgerRef, address: Address, slot: UInt256): bool = return sp = sp.parentSavepoint +func inAccessList*(ac: LedgerRef, codeHash: Hash32): bool = + var sp = ac.savePoint + while sp != nil: + result = sp.accessList.contains(codeHash) + if result: + return + sp = sp.parentSavepoint + func getAccessList*(ac: LedgerRef): transactions.AccessList = # make sure all savepoint already committed doAssert(ac.savePoint.parentSavepoint.isNil) diff --git a/execution_chain/evm/interpreter/op_handlers/oph_call.nim b/execution_chain/evm/interpreter/op_handlers/oph_call.nim index cefc26f954..66d47178dd 100644 --- a/execution_chain/evm/interpreter/op_handlers/oph_call.nim +++ b/execution_chain/evm/interpreter/op_handlers/oph_call.nim @@ -77,7 +77,7 @@ proc gasCallEIP7907(c: Computation, codeAddress: Address): GasInt = code = db.getCode(codeAddress) excessContractSize = max(0, code.len - CODE_SIZE_THRESHOLD) largeContractCost = (ceil32(excessContractSize) * 2) div 32 - return largeContractCost + return GasInt(largeContractCost) proc updateStackAndParams(q: var LocalParams; c: Computation) = c.stack.lsTop(0) From a7a4fc75db7783fea347d369307f81abb88eb574 Mon Sep 17 00:00:00 2001 From: chirag-parmar Date: Wed, 11 Jun 2025 18:42:41 +0530 Subject: [PATCH 3/7] copyright year update --- execution_chain/db/access_list.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/execution_chain/db/access_list.nim b/execution_chain/db/access_list.nim index b3662a8f16..adfe00586a 100644 --- a/execution_chain/db/access_list.nim +++ b/execution_chain/db/access_list.nim @@ -1,5 +1,5 @@ # Nimbus -# Copyright (c) 2023-2024 Status Research & Development GmbH +# Copyright (c) 2023-2025 Status Research & Development GmbH # Licensed under either of # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # http://www.apache.org/licenses/LICENSE-2.0) From 01d939e54b4545b2aa112c79d13918419f4df76f Mon Sep 17 00:00:00 2001 From: chirag-parmar Date: Thu, 12 Jun 2025 20:34:44 +0530 Subject: [PATCH 4/7] forked update --- execution_chain/constants.nim | 10 ++++++--- execution_chain/core/validate.nim | 8 +++++-- execution_chain/db/access_list.nim | 22 +++++++++---------- execution_chain/db/ledger.nim | 8 +++---- execution_chain/evm/computation.nim | 13 +++++++++++ .../evm/interpreter/op_handlers/oph_call.nim | 13 ----------- .../interpreter/op_handlers/oph_create.nim | 14 ++++++++---- .../interpreter/op_handlers/oph_helpers.nim | 19 ++++++++++++++++ .../withdrawals/wd_max_init_code_spec.nim | 2 +- vendor/constantine | 1 + 10 files changed, 72 insertions(+), 38 deletions(-) create mode 160000 vendor/constantine diff --git a/execution_chain/constants.nim b/execution_chain/constants.nim index 8ca1ad3782..fe5a36104f 100644 --- a/execution_chain/constants.nim +++ b/execution_chain/constants.nim @@ -59,15 +59,19 @@ const ## Fork specific constants - # See EIP-7907 (https://eips.ethereum.org/EIPS/eip-7907) Maximum code size + # See EIP-170 (https://eips.ethereum.org/EIPS/eip-170) Maximum code size # that can be stored for a new contract. Init code when creating a new # contract is not subject to this limit. + EIP170_SIZE_THRESHOLD* = 0x6000 + # See See EIP-170 (https://eips.ethereum.org/EIPS/eip-170). Update to limits CODE_SIZE_THRESHOLD* = 0x6000 EIP7907_MAX_CODE_SIZE* = 0x40000 - # See EIP-7907 (https://eips.ethereum.org/EIPS/eip-7907). Maximum initcode + # See EIP-3860 (https://eips.ethereum.org/EIPS/eip-3860). Maximum initcode # size when creating a new contract. - EIP7907_MAX_INITCODE_SIZE* = 0x80000 # 2 * EIP7907_MAX_CODE_SIZE + EIP3860_MAX_INITCODE_SIZE* = 2 * EIP170_MAX_CODE_SIZE + # See EIP-7907 (https://eips.ethereum.org/EIPS/eip-7907). + EIP7907_MAX_INITCODE_SIZE* = 2 * EIP7907_MAX_CODE_SIZE # EIP MaxPrecompilesAddr* = 0xFFFF diff --git a/execution_chain/core/validate.nim b/execution_chain/core/validate.nim index 8f1dc79656..dd317ee650 100644 --- a/execution_chain/core/validate.nim +++ b/execution_chain/core/validate.nim @@ -228,8 +228,12 @@ func validateTxBasic*( if tx.txType == TxEip7702 and fork < FkPrague: return err("invalid tx: Eip7702 Tx type detected before Prague") - if fork >= FkShanghai and tx.contractCreation and tx.payload.len > EIP7907_MAX_INITCODE_SIZE: - return err("invalid tx: initcode size exceeds maximum") + if tx.contractCreation: + if fork >= FkOsaka and tx.payload.len > EIP7907_MAX_INITCODE_SIZE: + return err("invalid tx: initcode size exceeds maximum") + elif fork >= FkShanghai and tx.payload.len > EIP3860_MAX_INITCODE_SIZE: + return err("invalid tx: initcode size exceeds maximum") + # The total must be the larger of the two if tx.maxFeePerGasNorm < tx.maxPriorityFeePerGasNorm: diff --git a/execution_chain/db/access_list.nim b/execution_chain/db/access_list.nim index adfe00586a..b4436a768a 100644 --- a/execution_chain/db/access_list.nim +++ b/execution_chain/db/access_list.nim @@ -21,7 +21,7 @@ type AccessList* = object slots: Table[Address, SlotSet] - codeHashes: seq[Hash32] + codeAddrs: seq[Address] # ------------------------------------------------------------------------------ # Private helpers @@ -37,7 +37,7 @@ func toStorageKeys(slots: SlotSet): seq[Bytes32] = proc init*(ac: var AccessList) = ac.slots = Table[Address, SlotSet]() - ac.codeHashes = newSeq[Hash32]() + ac.codeAddrs = newSeq[Address]() proc init*(_: type AccessList): AccessList {.inline.} = result.init() @@ -49,8 +49,8 @@ proc init*(_: type AccessList): AccessList {.inline.} = func contains*(ac: AccessList, address: Address): bool {.inline.} = address in ac.slots -func contains*(ac: AccessList, codeHash: Hash32): bool {.inline.} = - codeHash in ac.codeHashes +func containsCode*(ac: AccessList, codeAddr: Address): bool {.inline.} = + codeAddr in ac.codeAddrs # returnValue: (addressPresent, slotPresent) func contains*(ac: var AccessList, address: Address, slot: UInt256): bool = @@ -60,7 +60,7 @@ func contains*(ac: var AccessList, address: Address, slot: UInt256): bool = proc mergeAndReset*(ac, other: var AccessList) = # move values in `other` to `ac` ac.slots.mergeAndReset(other.slots) - ac.codeHashes.mergeAndReset(other.codeHashes) + ac.codeAddrs.mergeAndReset(other.codeAddrs) proc add*(ac: var AccessList, address: Address) = if address notin ac.slots: @@ -72,13 +72,13 @@ proc add*(ac: var AccessList, address: Address, slot: UInt256) = do: ac.slots[address] = toHashSet([slot]) -proc add*(ac: var AccessList, codeHash: Hash32) = - if codeHash notin ac.codeHashes: - ac.codeHashes.add(codeHash) +proc addCode*(ac: var AccessList, codeAddr: Address) = + if codeAddr notin ac.codeAddrs: + ac.codeAddrs.add(codeAddr) proc clear*(ac: var AccessList) {.inline.} = ac.slots.clear() - ac.codeHashes.setLen(0) + ac.codeAddrs.setLen(0) # TODO: accesses code is still not a part of the transaction access list # but when it does trickle down into the transaction we will have to add @@ -105,8 +105,8 @@ func equal*(ac: AccessList, other: var AccessList): bool = do: return false - for codeHash in ac.codeHashes: - if codeHash notin other: + for codeAddr in ac.codeAddrs: + if codeAddr notin other: return false true diff --git a/execution_chain/db/ledger.nim b/execution_chain/db/ledger.nim index 5d0d75a33c..f00ba698d4 100644 --- a/execution_chain/db/ledger.nim +++ b/execution_chain/db/ledger.nim @@ -829,8 +829,8 @@ proc accessList*(ac: LedgerRef, address: Address) = proc accessList*(ac: LedgerRef, address: Address, slot: UInt256) = ac.savePoint.accessList.add(address, slot) -proc accessList*(ac: LedgerRef, codeHash: Hash32) = - ac.savePoint.accessList.add(codeHash) +proc accessList*(ac: LedgerRef, codeAddr: Address) = + ac.savePoint.accessList.addCode(codeAddr) func inAccessList*(ac: LedgerRef, address: Address): bool = var sp = ac.savePoint @@ -848,10 +848,10 @@ func inAccessList*(ac: LedgerRef, address: Address, slot: UInt256): bool = return sp = sp.parentSavepoint -func inAccessList*(ac: LedgerRef, codeHash: Hash32): bool = +func inCodeAccessList*(ac: LedgerRef, codeAddr: Address): bool = var sp = ac.savePoint while sp != nil: - result = sp.accessList.contains(codeHash) + result = sp.accessList.containsCode(codeAddr) if result: return sp = sp.parentSavepoint diff --git a/execution_chain/evm/computation.nim b/execution_chain/evm/computation.nim index 94c2130ab7..b3b1e38642 100644 --- a/execution_chain/evm/computation.nim +++ b/execution_chain/evm/computation.nim @@ -207,10 +207,23 @@ proc writeContract*(c: Computation) = # EIP-170 constraint (https://eips.ethereum.org/EIPS/eip-3541). if fork >= FkSpurious and len > EIP7907_MAX_CODE_SIZE: + withExtra trace, "New contract code exceeds EIP-170 limit", + codeSize=len, maxSize=EIP170_MAX_CODE_SIZE + c.setError(StatusCode.OutOfGas, true) + return + + # EIP-7907 constraint (https://eips.ethereum.org/EIPS/eip-7907). + if fork >= FkOsaka and len > EIP7907_MAX_CODE_SIZE: withExtra trace, "New contract code exceeds EIP-7907 limit", codeSize=len, maxSize=EIP7907_MAX_CODE_SIZE c.setError(StatusCode.OutOfGas, true) return + # EIP-170 constraint (https://eips.ethereum.org/EIPS/eip-170). + elif fork >= FkSpurious and len > EIP7907_MAX_CODE_SIZE: + withExtra trace, "New contract code exceeds EIP-170 limit", + codeSize=len, maxSize=EIP170_MAX_CODE_SIZE + c.setError(StatusCode.OutOfGas, true) + return # Charge gas and write the code even if the code address is self-destructed. # Non-empty code in a newly created, self-destructed account is possible if diff --git a/execution_chain/evm/interpreter/op_handlers/oph_call.nim b/execution_chain/evm/interpreter/op_handlers/oph_call.nim index 66d47178dd..009710d182 100644 --- a/execution_chain/evm/interpreter/op_handlers/oph_call.nim +++ b/execution_chain/evm/interpreter/op_handlers/oph_call.nim @@ -66,19 +66,6 @@ proc gasCallEIP2929(c: Computation, address: Address): GasInt = # the form of a constant `gasCall` return ColdAccountAccessCost - WarmStorageReadCost -proc gasCallEIP7907(c: Computation, codeAddress: Address): GasInt = - c.vmState.mutateLedger: - let codeHash = db.getCodeHash(codeAddress) - - if not db.inAccessList(codeHash): - db.accessList(codeHash) - - let - code = db.getCode(codeAddress) - excessContractSize = max(0, code.len - CODE_SIZE_THRESHOLD) - largeContractCost = (ceil32(excessContractSize) * 2) div 32 - return GasInt(largeContractCost) - proc updateStackAndParams(q: var LocalParams; c: Computation) = c.stack.lsTop(0) diff --git a/execution_chain/evm/interpreter/op_handlers/oph_create.nim b/execution_chain/evm/interpreter/op_handlers/oph_create.nim index 5b83a8fa03..a123a72c3f 100644 --- a/execution_chain/evm/interpreter/op_handlers/oph_create.nim +++ b/execution_chain/evm/interpreter/op_handlers/oph_create.nim @@ -76,8 +76,11 @@ proc createOp(cpt: VmCpt): EvmResultVoid = cpt.stack.lsShrink(2) cpt.stack.lsTop(0) - # EIP-3860 - if cpt.fork >= FkShanghai and memLen > EIP7907_MAX_INITCODE_SIZE: + # EIP-7907 and EIP-3860 + if cpt.fork >= FkOsaka and memLen > EIP7907_MAX_INITCODE_SIZE: + trace "Initcode size exceeds maximum", initcodeSize = memLen + return err(opErr(InvalidInitCode)) + elif cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: trace "Initcode size exceeds maximum", initcodeSize = memLen return err(opErr(InvalidInitCode)) @@ -146,8 +149,11 @@ proc create2Op(cpt: VmCpt): EvmResultVoid = cpt.stack.lsShrink(3) cpt.stack.lsTop(0) - # EIP-3860 - if cpt.fork >= FkShanghai and memLen > EIP7907_MAX_INITCODE_SIZE: + # EIP-7907 and EIP-3860 + if cpt.fork >= FkOsaka and memLen > EIP7907_MAX_INITCODE_SIZE: + trace "Initcode size exceeds maximum", initcodeSize = memLen + return err(opErr(InvalidInitCode)) + elif cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: trace "Initcode size exceeds maximum", initcodeSize = memLen return err(opErr(InvalidInitCode)) diff --git a/execution_chain/evm/interpreter/op_handlers/oph_helpers.nim b/execution_chain/evm/interpreter/op_handlers/oph_helpers.nim index 55473a5109..401a48c4ea 100644 --- a/execution_chain/evm/interpreter/op_handlers/oph_helpers.nim +++ b/execution_chain/evm/interpreter/op_handlers/oph_helpers.nim @@ -59,6 +59,25 @@ proc delegateResolutionCost*(c: Computation, address: Address): GasInt = else: return WarmStorageReadCost +proc gasEip7702CodeCheck*(c: Computation; address: Address): GasInt = + let delegateTo = + parseDelegationAddress(c.vmState.readOnlyLedger.getCode(address)).valueOr: + return 0 + c.delegateResolutionCost(delegateTo) + +proc gasCallEIP7907*(c: Computation, codeAddress: Address): GasInt = + c.vmState.mutateLedger: + let codeHash = db.getCodeHash(codeAddress) + + if not db.inAccessList(codeHash): + db.accessList(codeHash) + + let + code = db.getCode(codeAddress) + excessContractSize = max(0, code.len - CODE_SIZE_THRESHOLD) + largeContractCost = (ceil32(excessContractSize) * 2) div 32 + return GasInt(largeContractCost) + # ------------------------------------------------------------------------------ # End # ------------------------------------------------------------------------------ diff --git a/hive_integration/nodocker/engine/withdrawals/wd_max_init_code_spec.nim b/hive_integration/nodocker/engine/withdrawals/wd_max_init_code_spec.nim index fa10039077..9e55ccc77e 100644 --- a/hive_integration/nodocker/engine/withdrawals/wd_max_init_code_spec.nim +++ b/hive_integration/nodocker/engine/withdrawals/wd_max_init_code_spec.nim @@ -32,7 +32,7 @@ type overflowMaxInitcodeTxCountAfterFork *: uint64 const - MAX_INITCODE_SIZE = EIP7907_MAX_INITCODE_SIZE + MAX_INITCODE_SIZE = EIP170_MAX_INITCODE_SIZE proc execute*(ws: MaxInitcodeSizeSpec, env: TestEnv): bool = testCond waitFor env.clMock.waitForTTD() diff --git a/vendor/constantine b/vendor/constantine new file mode 160000 index 0000000000..782d838e7a --- /dev/null +++ b/vendor/constantine @@ -0,0 +1 @@ +Subproject commit 782d838e7a073262750eff593af6dfff3ff832dd From 9044fb6e6c550e5a65d191f75f351a11a31979b7 Mon Sep 17 00:00:00 2001 From: chirag-parmar Date: Thu, 12 Jun 2025 20:46:06 +0530 Subject: [PATCH 5/7] add 7907 for ext code copy --- .../evm/interpreter/op_handlers/oph_defs.nim | 4 +++ .../interpreter/op_handlers/oph_envinfo.nim | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/execution_chain/evm/interpreter/op_handlers/oph_defs.nim b/execution_chain/evm/interpreter/op_handlers/oph_defs.nim index 7319542e0f..30550141ef 100644 --- a/execution_chain/evm/interpreter/op_handlers/oph_defs.nim +++ b/execution_chain/evm/interpreter/op_handlers/oph_defs.nim @@ -82,6 +82,10 @@ const VmOpCancunAndLater* = VmOpShanghaiAndLater - {FkShanghai} + VmOpOsakaAndLater* = + VmOpCancunAndLater - {FkCancun} + + # ------------------------------------------------------------------------------ # End # ------------------------------------------------------------------------------ diff --git a/execution_chain/evm/interpreter/op_handlers/oph_envinfo.nim b/execution_chain/evm/interpreter/op_handlers/oph_envinfo.nim index b519375a18..c5d4b18c16 100644 --- a/execution_chain/evm/interpreter/op_handlers/oph_envinfo.nim +++ b/execution_chain/evm/interpreter/op_handlers/oph_envinfo.nim @@ -189,6 +189,25 @@ proc extCodeCopyEIP2929Op(cpt: VmCpt): EvmResultVoid = cpt.memory.writePadded(code.bytes(), memPos, codePos, len) ok() +proc extCodeCopyEIP7907Op(cpt: VmCpt): EvmResultVoid = + ## 0x3c, Copy an account's code to memory (EIP-2929). + ? cpt.stack.lsCheck(4) + let + address = cpt.stack.lsPeekAddress(^1) + memPos = cpt.stack.lsPeekMemRef(^2) + codePos = cpt.stack.lsPeekMemRef(^3) + len = cpt.stack.lsPeekMemRef(^4) + gasCost = cpt.gasCosts[ExtCodeCopy].m_handler(cpt.memory.len, memPos, len) + + cpt.gasEip2929AccountCheck(address) + cpt.gasCallEIP7907(addresss) + + cpt.stack.lsShrink(4) + ? cpt.opcodeGasCost(ExtCodeCopy, gasCost, reason = "ExtCodeCopy EIP7907") + + let code = cpt.getCode(address) + cpt.memory.writePadded(code.bytes(), memPos, codePos, len) + ok() + + # ----------- func returnDataSizeOp(cpt: VmCpt): EvmResultVoid = @@ -350,6 +369,13 @@ const info: "EIP2929: Copy an account's code to memory", exec: extCodeCopyEIP2929Op), + (opCode: ExtCodeCopy, ## 0x3c, Account Code-copy for Berlin through Cancun + forks: VmOpOsakaAndLater, + name: "extCodeCopyEIP7907", + info: "EIP7907: Copy an account's code to memory", + exec: extCodeCopyEIP7907Op), + + (opCode: ReturnDataSize, ## 0x3d, Previous call output data size forks: VmOpByzantiumAndLater, From 4521cb41f08eb11df0c5f771b569676f0815fafc Mon Sep 17 00:00:00 2001 From: chirag-parmar Date: Fri, 13 Jun 2025 15:35:53 +0530 Subject: [PATCH 6/7] touch code --- execution_chain/constants.nim | 4 ++-- execution_chain/db/access_list.nim | 9 ++++----- execution_chain/db/ledger.nim | 2 +- execution_chain/evm/computation.nim | 2 +- .../evm/interpreter/op_handlers/oph_create.nim | 9 +++++++++ .../evm/interpreter/op_handlers/oph_defs.nim | 5 ++++- .../evm/interpreter/op_handlers/oph_envinfo.nim | 5 ++--- .../evm/interpreter/op_handlers/oph_helpers.nim | 13 ++++--------- .../engine/withdrawals/wd_max_init_code_spec.nim | 2 +- vendor/constantine | 1 - 10 files changed, 28 insertions(+), 24 deletions(-) delete mode 160000 vendor/constantine diff --git a/execution_chain/constants.nim b/execution_chain/constants.nim index fe5a36104f..61e5f48708 100644 --- a/execution_chain/constants.nim +++ b/execution_chain/constants.nim @@ -62,8 +62,8 @@ const # See EIP-170 (https://eips.ethereum.org/EIPS/eip-170) Maximum code size # that can be stored for a new contract. Init code when creating a new # contract is not subject to this limit. - EIP170_SIZE_THRESHOLD* = 0x6000 - # See See EIP-170 (https://eips.ethereum.org/EIPS/eip-170). Update to limits + EIP170_MAX_CODE_SIZE* = 0x6000 + # See See EIP-7907 (https://eips.ethereum.org/EIPS/eip-7907). Update to limits CODE_SIZE_THRESHOLD* = 0x6000 EIP7907_MAX_CODE_SIZE* = 0x40000 diff --git a/execution_chain/db/access_list.nim b/execution_chain/db/access_list.nim index b4436a768a..7e5b902c3c 100644 --- a/execution_chain/db/access_list.nim +++ b/execution_chain/db/access_list.nim @@ -21,7 +21,7 @@ type AccessList* = object slots: Table[Address, SlotSet] - codeAddrs: seq[Address] + codeAddrs: HashSet[Address] # ------------------------------------------------------------------------------ # Private helpers @@ -37,7 +37,7 @@ func toStorageKeys(slots: SlotSet): seq[Bytes32] = proc init*(ac: var AccessList) = ac.slots = Table[Address, SlotSet]() - ac.codeAddrs = newSeq[Address]() + ac.codeAddrs = HashSet[Address]() proc init*(_: type AccessList): AccessList {.inline.} = result.init() @@ -73,12 +73,11 @@ proc add*(ac: var AccessList, address: Address, slot: UInt256) = ac.slots[address] = toHashSet([slot]) proc addCode*(ac: var AccessList, codeAddr: Address) = - if codeAddr notin ac.codeAddrs: - ac.codeAddrs.add(codeAddr) + ac.codeAddrs.incl codeAddr proc clear*(ac: var AccessList) {.inline.} = ac.slots.clear() - ac.codeAddrs.setLen(0) + ac.codeAddrs.clear() # TODO: accesses code is still not a part of the transaction access list # but when it does trickle down into the transaction we will have to add diff --git a/execution_chain/db/ledger.nim b/execution_chain/db/ledger.nim index f00ba698d4..3037795ce7 100644 --- a/execution_chain/db/ledger.nim +++ b/execution_chain/db/ledger.nim @@ -829,7 +829,7 @@ proc accessList*(ac: LedgerRef, address: Address) = proc accessList*(ac: LedgerRef, address: Address, slot: UInt256) = ac.savePoint.accessList.add(address, slot) -proc accessList*(ac: LedgerRef, codeAddr: Address) = +proc codeAccessList*(ac: LedgerRef, codeAddr: Address) = ac.savePoint.accessList.addCode(codeAddr) func inAccessList*(ac: LedgerRef, address: Address): bool = diff --git a/execution_chain/evm/computation.nim b/execution_chain/evm/computation.nim index b3b1e38642..027c2bbfb0 100644 --- a/execution_chain/evm/computation.nim +++ b/execution_chain/evm/computation.nim @@ -219,7 +219,7 @@ proc writeContract*(c: Computation) = c.setError(StatusCode.OutOfGas, true) return # EIP-170 constraint (https://eips.ethereum.org/EIPS/eip-170). - elif fork >= FkSpurious and len > EIP7907_MAX_CODE_SIZE: + elif fork >= FkSpurious and len > EIP170_MAX_CODE_SIZE: withExtra trace, "New contract code exceeds EIP-170 limit", codeSize=len, maxSize=EIP170_MAX_CODE_SIZE c.setError(StatusCode.OutOfGas, true) diff --git a/execution_chain/evm/interpreter/op_handlers/oph_create.nim b/execution_chain/evm/interpreter/op_handlers/oph_create.nim index a123a72c3f..d6a341e950 100644 --- a/execution_chain/evm/interpreter/op_handlers/oph_create.nim +++ b/execution_chain/evm/interpreter/op_handlers/oph_create.nim @@ -117,6 +117,10 @@ proc createOp(cpt: VmCpt): EvmResultVoid = createMsgGas -= createMsgGas div 64 ? cpt.gasMeter.consumeGas(createMsgGas, reason = "CREATE msg gas") + if cpt.fork >= FkOsaka: + cpt.vmState.mutateLedger: + db.codeAccessList(cpt.msg.contractAddress) + var childMsg = Message( kind: CallKind.Create, @@ -187,6 +191,11 @@ proc create2Op(cpt: VmCpt): EvmResultVoid = balance = senderBalance return ok() + if cpt.fork >= FkOsaka: + cpt.vmState.mutateLedger: + db.codeAccessList(cpt.msg.contractAddress) + + var createMsgGas = cpt.gasMeter.gasRemaining if cpt.fork >= FkTangerine: createMsgGas -= createMsgGas div 64 diff --git a/execution_chain/evm/interpreter/op_handlers/oph_defs.nim b/execution_chain/evm/interpreter/op_handlers/oph_defs.nim index 30550141ef..a41f484250 100644 --- a/execution_chain/evm/interpreter/op_handlers/oph_defs.nim +++ b/execution_chain/evm/interpreter/op_handlers/oph_defs.nim @@ -82,9 +82,12 @@ const VmOpCancunAndLater* = VmOpShanghaiAndLater - {FkShanghai} - VmOpOsakaAndLater* = + VmOpPragueAndLater* = VmOpCancunAndLater - {FkCancun} + VmOpOsakaAndLater* = + VmOpPragueAndLater - {FkPrague} + # ------------------------------------------------------------------------------ # End diff --git a/execution_chain/evm/interpreter/op_handlers/oph_envinfo.nim b/execution_chain/evm/interpreter/op_handlers/oph_envinfo.nim index c5d4b18c16..aa2d540f4e 100644 --- a/execution_chain/evm/interpreter/op_handlers/oph_envinfo.nim +++ b/execution_chain/evm/interpreter/op_handlers/oph_envinfo.nim @@ -198,7 +198,7 @@ proc extCodeCopyEIP7907Op(cpt: VmCpt): EvmResultVoid = codePos = cpt.stack.lsPeekMemRef(^3) len = cpt.stack.lsPeekMemRef(^4) gasCost = cpt.gasCosts[ExtCodeCopy].m_handler(cpt.memory.len, memPos, len) + - cpt.gasEip2929AccountCheck(address) + cpt.gasCallEIP7907(addresss) + cpt.gasEip2929AccountCheck(address) + cpt.gasCallEIP7907(address) cpt.stack.lsShrink(4) ? cpt.opcodeGasCost(ExtCodeCopy, gasCost, reason = "ExtCodeCopy EIP7907") @@ -207,7 +207,6 @@ proc extCodeCopyEIP7907Op(cpt: VmCpt): EvmResultVoid = cpt.memory.writePadded(code.bytes(), memPos, codePos, len) ok() - # ----------- func returnDataSizeOp(cpt: VmCpt): EvmResultVoid = @@ -364,7 +363,7 @@ const (opCode: ExtCodeCopy, ## 0x3c, Account Code-copy for Berlin through Cancun - forks: VmOpBerlinAndLater, + forks: VmOpBerlinAndLater - VmOpOsakaAndLater, name: "extCodeCopyEIP2929", info: "EIP2929: Copy an account's code to memory", exec: extCodeCopyEIP2929Op), diff --git a/execution_chain/evm/interpreter/op_handlers/oph_helpers.nim b/execution_chain/evm/interpreter/op_handlers/oph_helpers.nim index 401a48c4ea..f06026b03a 100644 --- a/execution_chain/evm/interpreter/op_handlers/oph_helpers.nim +++ b/execution_chain/evm/interpreter/op_handlers/oph_helpers.nim @@ -15,7 +15,9 @@ {.push raises: [].} import + ../../../constants, ../../evm_errors, + ../../interpreter/utils/utils_numeric, ../../types, ../gas_costs, eth/common/[addresses, base], @@ -59,18 +61,11 @@ proc delegateResolutionCost*(c: Computation, address: Address): GasInt = else: return WarmStorageReadCost -proc gasEip7702CodeCheck*(c: Computation; address: Address): GasInt = - let delegateTo = - parseDelegationAddress(c.vmState.readOnlyLedger.getCode(address)).valueOr: - return 0 - c.delegateResolutionCost(delegateTo) - proc gasCallEIP7907*(c: Computation, codeAddress: Address): GasInt = c.vmState.mutateLedger: - let codeHash = db.getCodeHash(codeAddress) - if not db.inAccessList(codeHash): - db.accessList(codeHash) + if not db.inCodeAccessList(codeAddress): + db.codeAccessList(codeAddress) let code = db.getCode(codeAddress) diff --git a/hive_integration/nodocker/engine/withdrawals/wd_max_init_code_spec.nim b/hive_integration/nodocker/engine/withdrawals/wd_max_init_code_spec.nim index 9e55ccc77e..e9bbf1d5af 100644 --- a/hive_integration/nodocker/engine/withdrawals/wd_max_init_code_spec.nim +++ b/hive_integration/nodocker/engine/withdrawals/wd_max_init_code_spec.nim @@ -32,7 +32,7 @@ type overflowMaxInitcodeTxCountAfterFork *: uint64 const - MAX_INITCODE_SIZE = EIP170_MAX_INITCODE_SIZE + MAX_INITCODE_SIZE = EIP3860_MAX_INITCODE_SIZE proc execute*(ws: MaxInitcodeSizeSpec, env: TestEnv): bool = testCond waitFor env.clMock.waitForTTD() diff --git a/vendor/constantine b/vendor/constantine deleted file mode 160000 index 782d838e7a..0000000000 --- a/vendor/constantine +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 782d838e7a073262750eff593af6dfff3ff832dd From 302e2eed206ec9687df66be02cb6ef0b43e1c1a3 Mon Sep 17 00:00:00 2001 From: chirag-parmar Date: Fri, 13 Jun 2025 18:00:57 +0530 Subject: [PATCH 7/7] better if conditions --- execution_chain/core/validate.nim | 3 ++- execution_chain/evm/computation.nim | 10 ++-------- .../evm/interpreter/op_handlers/oph_create.nim | 6 ++++-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/execution_chain/core/validate.nim b/execution_chain/core/validate.nim index dd317ee650..8c0d7d4825 100644 --- a/execution_chain/core/validate.nim +++ b/execution_chain/core/validate.nim @@ -231,7 +231,8 @@ func validateTxBasic*( if tx.contractCreation: if fork >= FkOsaka and tx.payload.len > EIP7907_MAX_INITCODE_SIZE: return err("invalid tx: initcode size exceeds maximum") - elif fork >= FkShanghai and tx.payload.len > EIP3860_MAX_INITCODE_SIZE: + + if fork < FkOsaka and fork >= FkShanghai and tx.payload.len > EIP3860_MAX_INITCODE_SIZE: return err("invalid tx: initcode size exceeds maximum") diff --git a/execution_chain/evm/computation.nim b/execution_chain/evm/computation.nim index 027c2bbfb0..f2cffa2b81 100644 --- a/execution_chain/evm/computation.nim +++ b/execution_chain/evm/computation.nim @@ -205,21 +205,15 @@ proc writeContract*(c: Computation) = c.setError(StatusCode.ContractValidationFailure, true) return - # EIP-170 constraint (https://eips.ethereum.org/EIPS/eip-3541). - if fork >= FkSpurious and len > EIP7907_MAX_CODE_SIZE: - withExtra trace, "New contract code exceeds EIP-170 limit", - codeSize=len, maxSize=EIP170_MAX_CODE_SIZE - c.setError(StatusCode.OutOfGas, true) - return - # EIP-7907 constraint (https://eips.ethereum.org/EIPS/eip-7907). if fork >= FkOsaka and len > EIP7907_MAX_CODE_SIZE: withExtra trace, "New contract code exceeds EIP-7907 limit", codeSize=len, maxSize=EIP7907_MAX_CODE_SIZE c.setError(StatusCode.OutOfGas, true) return + # EIP-170 constraint (https://eips.ethereum.org/EIPS/eip-170). - elif fork >= FkSpurious and len > EIP170_MAX_CODE_SIZE: + if fork < FkOsaka and fork >= FkSpurious and len > EIP170_MAX_CODE_SIZE: withExtra trace, "New contract code exceeds EIP-170 limit", codeSize=len, maxSize=EIP170_MAX_CODE_SIZE c.setError(StatusCode.OutOfGas, true) diff --git a/execution_chain/evm/interpreter/op_handlers/oph_create.nim b/execution_chain/evm/interpreter/op_handlers/oph_create.nim index d6a341e950..e80f974dcb 100644 --- a/execution_chain/evm/interpreter/op_handlers/oph_create.nim +++ b/execution_chain/evm/interpreter/op_handlers/oph_create.nim @@ -80,7 +80,8 @@ proc createOp(cpt: VmCpt): EvmResultVoid = if cpt.fork >= FkOsaka and memLen > EIP7907_MAX_INITCODE_SIZE: trace "Initcode size exceeds maximum", initcodeSize = memLen return err(opErr(InvalidInitCode)) - elif cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: + + if cpt.fork < FkOsaka and cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: trace "Initcode size exceeds maximum", initcodeSize = memLen return err(opErr(InvalidInitCode)) @@ -157,7 +158,8 @@ proc create2Op(cpt: VmCpt): EvmResultVoid = if cpt.fork >= FkOsaka and memLen > EIP7907_MAX_INITCODE_SIZE: trace "Initcode size exceeds maximum", initcodeSize = memLen return err(opErr(InvalidInitCode)) - elif cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: + + if cpt.fork < FkOsaka and cpt.fork >= FkShanghai and memLen > EIP3860_MAX_INITCODE_SIZE: trace "Initcode size exceeds maximum", initcodeSize = memLen return err(opErr(InvalidInitCode))