Skip to content

Commit

Permalink
perf: always spend gas
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniPopes committed Dec 22, 2024
1 parent 2ebed31 commit 4cb49fa
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 10 deletions.
2 changes: 2 additions & 0 deletions crates/handler/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,7 @@ pub fn return_create<JOURNAL: Journal>(
}
let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
if !interpreter_result.gas.record_cost(gas_for_code) {
interpreter_result.gas.spend_all();
// Record code deposit gas cost and check if we are out of gas.
// EIP-2 point 3: If contract creation does not have enough gas to pay for the
// final gas fee for adding the contract code to the state, the contract
Expand Down Expand Up @@ -777,6 +778,7 @@ pub fn return_eofcreate<JOURNAL: Journal>(
// Deduct gas for code deployment.
let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
if !interpreter_result.gas.record_cost(gas_for_code) {
interpreter_result.gas.spend_all();
journal.checkpoint_revert(checkpoint);
interpreter_result.result = InstructionResult::OutOfGas;
return;
Expand Down
4 changes: 2 additions & 2 deletions crates/handler/src/precompile_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ where

match (*precompile)(bytes, gas_limit) {
Ok(output) => {
let underflow = result.gas.record_cost(output.gas_used);
assert!(underflow, "Gas underflow is not possible");
let success = result.gas.record_cost(output.gas_used);
assert!(success, "Gas underflow is not possible");
result.result = InstructionResult::Return;
result.output = output.bytes;
}
Expand Down
21 changes: 14 additions & 7 deletions crates/interpreter/src/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ impl Gas {
self.remaining += returned;
}

/// Spends all remaining gas if it overflowed.
#[inline]
pub fn spend_all_if_overflowed(&mut self) {
if self.remaining > self.limit {
self.spend_all();
}
}

/// Spends all remaining gas.
#[inline]
pub fn spend_all(&mut self) {
Expand Down Expand Up @@ -122,15 +130,14 @@ impl Gas {
/// Records an explicit cost.
///
/// Returns `false` if the gas limit is exceeded.
#[inline]
/// In this case, the remaining gas will overflow, which should be handled after execution.
/// See [`spend_all_if_overflowed`](Self::spend_all_if_overflowed).
#[inline(always)]
#[must_use = "prefer using `gas!` instead to return an out-of-gas error on failure"]
pub fn record_cost(&mut self, cost: u64) -> bool {
let (remaining, overflow) = self.remaining.overflowing_sub(cost);
let success = !overflow;
if success {
self.remaining = remaining;
}
success
let overflow;
(self.remaining, overflow) = self.remaining.overflowing_sub(cost);
!overflow
}

/// Record memory expansion
Expand Down
5 changes: 4 additions & 1 deletion crates/interpreter/src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,14 @@ impl<IW: InterpreterTypes> Interpreter<IW> {
self.control
.set_next_action(InterpreterAction::None, InstructionResult::Continue);

// Main loop
// Main loop.
while self.control.instruction_result().is_continue() {
self.step(instruction_table, host);
}

// Set gas to 0 if it overflowed.
self.control.gas().spend_all_if_overflowed();

// Return next action if it is some.
let action = self.control.take_next_action();
if action.is_some() {
Expand Down

0 comments on commit 4cb49fa

Please sign in to comment.