Skip to content
Draft
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion execution_chain/constants.nim
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,19 @@ const

## Fork specific constants

# See EIP-170 (https://eips.ethereum.org/EIPS/eip-170). 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_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

# See EIP-3860 (https://eips.ethereum.org/EIPS/eip-3860). Maximum initcode
# size when creating a new contract.
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
Expand Down
8 changes: 6 additions & 2 deletions execution_chain/core/validate.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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 > EIP3860_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:
Expand Down
19 changes: 18 additions & 1 deletion execution_chain/db/access_list.nim
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -21,6 +21,7 @@ type

AccessList* = object
slots: Table[Address, SlotSet]
codeAddrs: HashSet[Address]

# ------------------------------------------------------------------------------
# Private helpers
Expand All @@ -36,6 +37,7 @@ func toStorageKeys(slots: SlotSet): seq[Bytes32] =

proc init*(ac: var AccessList) =
ac.slots = Table[Address, SlotSet]()
ac.codeAddrs = HashSet[Address]()

proc init*(_: type AccessList): AccessList {.inline.} =
result.init()
Expand All @@ -47,6 +49,9 @@ proc init*(_: type AccessList): AccessList {.inline.} =
func contains*(ac: AccessList, address: Address): bool {.inline.} =
address in ac.slots

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 =
ac.slots.withValue(address, val):
Expand All @@ -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.codeAddrs.mergeAndReset(other.codeAddrs)

proc add*(ac: var AccessList, address: Address) =
if address notin ac.slots:
Expand All @@ -66,9 +72,16 @@ proc add*(ac: var AccessList, address: Address, slot: UInt256) =
do:
ac.slots[address] = toHashSet([slot])

proc addCode*(ac: var AccessList, codeAddr: Address) =
ac.codeAddrs.incl codeAddr

proc clear*(ac: var AccessList) {.inline.} =
ac.slots.clear()
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
# it here
func getAccessList*(ac: AccessList): transactions.AccessList =
for address, slots in ac.slots:
result.add transactions.AccessPair(
Expand All @@ -91,4 +104,8 @@ func equal*(ac: AccessList, other: var AccessList): bool =
do:
return false

for codeAddr in ac.codeAddrs:
if codeAddr notin other:
return false

true
11 changes: 11 additions & 0 deletions execution_chain/db/ledger.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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 codeAccessList*(ac: LedgerRef, codeAddr: Address) =
ac.savePoint.accessList.addCode(codeAddr)

func inAccessList*(ac: LedgerRef, address: Address): bool =
var sp = ac.savePoint
while sp != nil:
Expand All @@ -845,6 +848,14 @@ func inAccessList*(ac: LedgerRef, address: Address, slot: UInt256): bool =
return
sp = sp.parentSavepoint

func inCodeAccessList*(ac: LedgerRef, codeAddr: Address): bool =
var sp = ac.savePoint
while sp != nil:
result = sp.accessList.containsCode(codeAddr)
if result:
return
sp = sp.parentSavepoint

func getAccessList*(ac: LedgerRef): transactions.AccessList =
# make sure all savepoint already committed
doAssert(ac.savePoint.parentSavepoint.isNil)
Expand Down
15 changes: 14 additions & 1 deletion execution_chain/evm/computation.nim
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,20 @@ proc writeContract*(c: Computation) =
return

# EIP-170 constraint (https://eips.ethereum.org/EIPS/eip-3541).
if fork >= FkSpurious and len > EIP170_MAX_CODE_SIZE:
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:
withExtra trace, "New contract code exceeds EIP-170 limit",
codeSize=len, maxSize=EIP170_MAX_CODE_SIZE
c.setError(StatusCode.OutOfGas, true)
Expand Down
6 changes: 5 additions & 1 deletion execution_chain/evm/interpreter/op_handlers/oph_call.nim
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,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))
Expand Down
23 changes: 19 additions & 4 deletions execution_chain/evm/interpreter/op_handlers/oph_create.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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 > EIP3860_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))

Expand Down Expand Up @@ -114,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,
Expand Down Expand Up @@ -146,8 +153,11 @@ proc create2Op(cpt: VmCpt): EvmResultVoid =
cpt.stack.lsShrink(3)
cpt.stack.lsTop(0)

# EIP-3860
if cpt.fork >= FkShanghai and memLen > EIP3860_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))

Expand Down Expand Up @@ -181,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
Expand Down
7 changes: 7 additions & 0 deletions execution_chain/evm/interpreter/op_handlers/oph_defs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ const
VmOpCancunAndLater* =
VmOpShanghaiAndLater - {FkShanghai}

VmOpPragueAndLater* =
VmOpCancunAndLater - {FkCancun}

VmOpOsakaAndLater* =
VmOpPragueAndLater - {FkPrague}


# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------
27 changes: 26 additions & 1 deletion execution_chain/evm/interpreter/op_handlers/oph_envinfo.nim
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,24 @@ 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(address)

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 =
Expand Down Expand Up @@ -345,11 +363,18 @@ 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),

(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,
Expand Down
14 changes: 14 additions & 0 deletions execution_chain/evm/interpreter/op_handlers/oph_helpers.nim
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
{.push raises: [].}

import
../../../constants,
../../evm_errors,
../../interpreter/utils/utils_numeric,
../../types,
../gas_costs,
eth/common/[addresses, base],
Expand Down Expand Up @@ -59,6 +61,18 @@ proc delegateResolutionCost*(c: Computation, address: Address): GasInt =
else:
return WarmStorageReadCost

proc gasCallEIP7907*(c: Computation, codeAddress: Address): GasInt =
c.vmState.mutateLedger:

if not db.inCodeAccessList(codeAddress):
db.codeAccessList(codeAddress)

let
code = db.getCode(codeAddress)
excessContractSize = max(0, code.len - CODE_SIZE_THRESHOLD)
largeContractCost = (ceil32(excessContractSize) * 2) div 32
return GasInt(largeContractCost)

# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------
Loading