Skip to content

Commit c62024e

Browse files
authored
devnet-5: Add EIP-7623: Increase calldata cost (#3015)
* devnet5: Add EIP-7623: Increase calldata cost * Fix copyright year
1 parent 234487a commit c62024e

File tree

5 files changed

+61
-28
lines changed

5 files changed

+61
-28
lines changed

nimbus/core/validate.nim

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,12 @@ proc validateTxBasic*(
231231
if tx.maxFeePerGasNorm < tx.maxPriorityFeePerGasNorm:
232232
return err(&"invalid tx: maxFee is smaller than maxPriorityFee. maxFee={tx.maxFeePerGas}, maxPriorityFee={tx.maxPriorityFeePerGasNorm}")
233233

234-
if tx.gasLimit < tx.intrinsicGas(fork):
235-
return err(&"invalid tx: not enough gas to perform calculation. avail={tx.gasLimit}, require={tx.intrinsicGas(fork)}")
234+
let
235+
(intrinsicGas, floorDataGas) = tx.intrinsicGas(fork)
236+
minGasLimit = max(intrinsicGas, floorDataGas)
237+
238+
if tx.gasLimit < minGasLimit:
239+
return err(&"invalid tx: not enough gas to perform calculation. avail={tx.gasLimit}, require={minGasLimit}")
236240

237241
if fork >= FkCancun:
238242
if tx.payload.len > MAX_CALLDATA_SIZE:

nimbus/transaction/call_common.nim

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Nimbus - Common entry point to the EVM from all different callers
22
#
3-
# Copyright (c) 2018-2024 Status Research & Development GmbH
3+
# Copyright (c) 2018-2025 Status Research & Development GmbH
44
# Licensed under either of
55
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
66
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
@@ -143,8 +143,8 @@ proc setupHost(call: CallParams, keepStack: bool): TransactionHost =
143143
vmState.gasRefunded = 0
144144

145145
let
146-
intrinsicGas = if call.noIntrinsic: 0.GasInt
147-
else: intrinsicGas(call, vmState.fork)
146+
(intrinsicGas, floorDataGas) = if call.noIntrinsic: (0.GasInt, 0.GasInt)
147+
else: intrinsicGas(call, vmState.fork)
148148
host = TransactionHost(
149149
vmState: vmState,
150150
sysCall: call.sysCall,
@@ -157,7 +157,8 @@ proc setupHost(call: CallParams, keepStack: bool): TransactionHost =
157157
code_address: call.to.toEvmc,
158158
sender: call.sender.toEvmc,
159159
value: call.value.toEvmc,
160-
)
160+
),
161+
floorDataGas: floorDataGas,
161162
# All other defaults in `TransactionHost` are fine.
162163
)
163164
gasRefund = if call.sysCall: 0
@@ -235,38 +236,50 @@ proc prepareToRunComputation(host: TransactionHost, call: CallParams) =
235236
db.subBalance(call.sender, blobFee)
236237

237238
proc calculateAndPossiblyRefundGas(host: TransactionHost, call: CallParams): GasInt =
238-
let c = host.computation
239+
let
240+
c = host.computation
241+
fork = host.vmState.fork
239242

240243
# EIP-3529: Reduction in refunds
241-
let MaxRefundQuotient = if host.vmState.fork >= FkLondon:
244+
let MaxRefundQuotient = if fork >= FkLondon:
242245
5.GasInt
243246
else:
244247
2.GasInt
245248

249+
var gasRemaining = 0.GasInt
250+
246251
# Calculated gas used, taking into account refund rules.
247252
if call.noRefund:
248-
result = c.gasMeter.gasRemaining
253+
gasRemaining = c.gasMeter.gasRemaining
249254
else:
250255
if c.shouldBurnGas:
251256
c.gasMeter.gasRemaining = 0
252257
let maxRefund = (call.gasLimit - c.gasMeter.gasRemaining) div MaxRefundQuotient
253258
let refund = min(c.getGasRefund(), maxRefund)
254259
c.gasMeter.returnGas(refund)
255-
result = c.gasMeter.gasRemaining
260+
gasRemaining = c.gasMeter.gasRemaining
261+
262+
let gasUsed = call.gasLimit - gasRemaining
263+
if fork >= FkPrague:
264+
if host.floorDataGas > gasUsed:
265+
gasRemaining = call.gasLimit - host.floorDataGas
266+
c.gasMeter.gasRemaining = gasRemaining
256267

257268
# Refund for unused gas.
258-
if result > 0 and not call.noGasCharge:
269+
if gasRemaining > 0 and not call.noGasCharge:
259270
host.vmState.mutateLedger:
260-
db.addBalance(call.sender, result.u256 * call.gasPrice.u256)
271+
db.addBalance(call.sender, gasRemaining.u256 * call.gasPrice.u256)
272+
273+
gasRemaining
261274

262275
proc finishRunningComputation(
263276
host: TransactionHost, call: CallParams, T: type): T =
264277
let c = host.computation
265278

266279
let gasRemaining = calculateAndPossiblyRefundGas(host, call)
267280
# evm gas used without intrinsic gas
268-
let gasUsed = host.msg.gas.GasInt - gasRemaining
269-
host.vmState.captureEnd(c, c.output, gasUsed, c.errorOpt)
281+
let evmGasUsed = host.msg.gas.GasInt - gasRemaining
282+
host.vmState.captureEnd(c, c.output, evmGasUsed, c.errorOpt)
270283

271284
when T is CallResult|DebugCallResult:
272285
# Collecting the result can be unnecessarily expensive when (re)-processing

nimbus/transaction/call_evm.nim

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Nimbus - Various ways of calling the EVM
22
#
3-
# Copyright (c) 2018-2024 Status Research & Development GmbH
3+
# Copyright (c) 2018-2025 Status Research & Development GmbH
44
# Licensed under either of
55
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
66
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
@@ -118,11 +118,13 @@ proc rpcEstimateGas*(args: TransactionArgs,
118118
hi = gasCap
119119

120120
cap = hi
121-
let intrinsicGas = intrinsicGas(params, fork)
121+
let
122+
(intrinsicGas, floorDataGas) = intrinsicGas(params, fork)
123+
minGasLimit = max(intrinsicGas, floorDataGas)
122124

123125
# Create a helper to check if a gas allowance results in an executable transaction
124126
proc executable(gasLimit: GasInt): EvmResult[bool] =
125-
if intrinsicGas > gasLimit:
127+
if minGasLimit > gasLimit:
126128
# Special case, raise gas limit
127129
return ok(true)
128130

nimbus/transaction/call_types.nim

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Nimbus
2-
# Copyright (c) 2024 Status Research & Development GmbH
2+
# Copyright (c) 2024-2025 Status Research & Development GmbH
33
# Licensed under either of
44
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
55
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
@@ -61,31 +61,44 @@ template input(tx: Transaction): auto =
6161
func isError*(cr: CallResult): bool =
6262
cr.error.len > 0
6363

64-
func intrinsicGas*(call: CallParams | Transaction, fork: EVMFork): GasInt =
64+
const
65+
TOTAL_COST_FLOOR_PER_TOKEN = 10
66+
67+
func intrinsicGas*(call: CallParams | Transaction, fork: EVMFork): (GasInt, GasInt) =
6568
# Compute the baseline gas cost for this transaction. This is the amount
6669
# of gas needed to send this transaction (but that is not actually used
6770
# for computation).
68-
var gas = gasFees[fork][GasTransaction]
71+
var
72+
intrinsicGas = gasFees[fork][GasTransaction]
73+
floorDataGas = intrinsicGas
74+
tokens = 0
6975

7076
# EIP-2 (Homestead) extra intrinsic gas for contract creations.
7177
if call.isCreate:
72-
gas += gasFees[fork][GasTXCreate]
78+
intrinsicGas += gasFees[fork][GasTXCreate]
7379
if fork >= FkShanghai:
74-
gas += (gasFees[fork][GasInitcodeWord] * call.input.len.wordCount)
80+
intrinsicGas += (gasFees[fork][GasInitcodeWord] * call.input.len.wordCount)
7581

7682
# Input data cost, reduced in EIP-2028 (Istanbul).
7783
let gasZero = gasFees[fork][GasTXDataZero]
7884
let gasNonZero = gasFees[fork][GasTXDataNonZero]
7985
for b in call.input:
80-
gas += (if b == 0: gasZero else: gasNonZero)
86+
if b == 0:
87+
intrinsicGas += gasZero
88+
tokens += 1
89+
else:
90+
intrinsicGas += gasNonZero
91+
tokens += 4
92+
8193

8294
# EIP-2930 (Berlin) intrinsic gas for transaction access list.
8395
if fork >= FkBerlin:
8496
for account in call.accessList:
85-
gas += ACCESS_LIST_ADDRESS_COST
86-
gas += GasInt(account.storageKeys.len) * ACCESS_LIST_STORAGE_KEY_COST
97+
intrinsicGas += ACCESS_LIST_ADDRESS_COST
98+
intrinsicGas += GasInt(account.storageKeys.len) * ACCESS_LIST_STORAGE_KEY_COST
8799

88100
if fork >= FkPrague:
89-
gas += call.authorizationList.len * PER_EMPTY_ACCOUNT_COST
101+
intrinsicGas += call.authorizationList.len * PER_EMPTY_ACCOUNT_COST
102+
floorDataGas += tokens * TOTAL_COST_FLOOR_PER_TOKEN
90103

91-
return gas.GasInt
104+
return (intrinsicGas.GasInt, floorDataGas.GasInt)

nimbus/transaction/host_types.nim

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Nimbus - Types and helpers used at the boundary of transactions/RPC and EVMC/EVM
22
#
3-
# Copyright (c) 2019-2024 Status Research & Development GmbH
3+
# Copyright (c) 2019-2025 Status Research & Development GmbH
44
# Licensed under either of
55
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
66
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
@@ -66,6 +66,7 @@ type
6666
saveComputation*: seq[Computation]
6767
hostInterface*: ptr evmc_host_interface
6868
sysCall*: bool
69+
floorDataGas*: GasInt
6970

7071
# These versions of `toEvmc` and `fromEvmc` don't flip big/little-endian like
7172
# the older functions in `evmc_helpers`. New code only flips with _explicit_

0 commit comments

Comments
 (0)