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
237238proc 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
262275proc 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
0 commit comments