From c6c2409d6338af5c2dc11d8cdc4cd3f410cd4d54 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Mon, 25 Mar 2024 11:00:11 +0100 Subject: [PATCH] perf(interpreter): keep track of remaining gas rather than spent (#1221) --- crates/interpreter/src/gas.rs | 64 ++++++++++--------- crates/revm/src/handler/mainnet/execution.rs | 8 +-- .../src/handler/mainnet/post_execution.rs | 4 +- crates/revm/src/optimism/handler_register.rs | 12 ++-- 4 files changed, 45 insertions(+), 43 deletions(-) diff --git a/crates/interpreter/src/gas.rs b/crates/interpreter/src/gas.rs index 9a37bf67ee1..01598cc159e 100644 --- a/crates/interpreter/src/gas.rs +++ b/crates/interpreter/src/gas.rs @@ -10,13 +10,13 @@ use revm_primitives::{Spec, SpecId::LONDON}; /// Represents the state of gas during execution. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] pub struct Gas { - /// The initial gas limit. + /// The initial gas limit. This is constant throughout execution. limit: u64, - /// The total used gas. - all_used_gas: u64, - /// Used gas without memory expansion. - used: u64, - /// Used gas for memory expansion. + /// The remaining gas. + remaining: u64, + /// The remaining gas, without memory expansion. + remaining_nomem: u64, + /// The **last** memory expansion cost. memory: u64, /// Refunded gas. This is used only at the end of execution. refunded: i64, @@ -28,10 +28,10 @@ impl Gas { pub const fn new(limit: u64) -> Self { Self { limit, - used: 0, + remaining: limit, + remaining_nomem: limit, memory: 0, refunded: 0, - all_used_gas: 0, } } @@ -41,35 +41,42 @@ impl Gas { self.limit } - /// Returns the amount of gas that was used. + /// Returns the **last** memory expansion cost. #[inline] pub const fn memory(&self) -> u64 { self.memory } - /// Returns the amount of gas that was refunded. + /// Returns the total amount of gas that was refunded. #[inline] pub const fn refunded(&self) -> i64 { self.refunded } - /// Returns all the gas used in the execution. + /// Returns the total amount of gas spent. #[inline] + pub const fn spent(&self) -> u64 { + self.limit - self.remaining + } + + #[doc(hidden)] + #[inline] + #[deprecated(note = "use `spent` instead")] pub const fn spend(&self) -> u64 { - self.all_used_gas + self.spent() } /// Returns the amount of gas remaining. #[inline] pub const fn remaining(&self) -> u64 { - self.limit - self.all_used_gas + self.remaining } /// Erases a gas cost from the totals. #[inline] pub fn erase_cost(&mut self, returned: u64) { - self.used -= returned; - self.all_used_gas -= returned; + self.remaining_nomem += returned; + self.remaining += returned; } /// Records a refund value. @@ -86,12 +93,14 @@ impl Gas { /// Max refund value is limited to Nth part (depending of fork) of gas spend. /// /// Related to EIP-3529: Reduction in refunds + #[inline] pub fn set_final_refund(&mut self) { let max_refund_quotient = if SPEC::enabled(LONDON) { 5 } else { 2 }; - self.refunded = (self.refunded() as u64).min(self.spend() / max_refund_quotient) as i64; + self.refunded = (self.refunded() as u64).min(self.spent() / max_refund_quotient) as i64; } - /// Set a refund value + /// Set a refund value. This overrides the current refund value. + #[inline] pub fn set_refund(&mut self, refund: i64) { self.refunded = refund; } @@ -101,13 +110,13 @@ impl Gas { /// Returns `false` if the gas limit is exceeded. #[inline(always)] pub fn record_cost(&mut self, cost: u64) -> bool { - let all_used_gas = self.all_used_gas.saturating_add(cost); - if self.limit < all_used_gas { + let (remaining, overflow) = self.remaining.overflowing_sub(cost); + if overflow { return false; } - self.used += cost; - self.all_used_gas = all_used_gas; + self.remaining_nomem -= cost; + self.remaining = remaining; true } @@ -117,20 +126,13 @@ impl Gas { #[inline] pub fn record_memory(&mut self, gas_memory: u64) -> bool { if gas_memory > self.memory { - let all_used_gas = self.used.saturating_add(gas_memory); - if self.limit < all_used_gas { + let (remaining, overflow) = self.remaining_nomem.overflowing_sub(gas_memory); + if overflow { return false; } self.memory = gas_memory; - self.all_used_gas = all_used_gas; + self.remaining = remaining; } true } - - #[doc(hidden)] - #[deprecated = "use `record_refund` instead"] - #[inline] - pub fn gas_refund(&mut self, refund: i64) { - self.record_refund(refund); - } } diff --git a/crates/revm/src/handler/mainnet/execution.rs b/crates/revm/src/handler/mainnet/execution.rs index 941d3b8fd4b..dc1514ea8ba 100644 --- a/crates/revm/src/handler/mainnet/execution.rs +++ b/crates/revm/src/handler/mainnet/execution.rs @@ -165,7 +165,7 @@ mod tests { fn test_consume_gas() { let gas = call_last_frame_return(InstructionResult::Stop, Gas::new(90)); assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spend(), 10); + assert_eq!(gas.spent(), 10); assert_eq!(gas.refunded(), 0); } @@ -177,12 +177,12 @@ mod tests { let gas = call_last_frame_return(InstructionResult::Stop, return_gas); assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spend(), 10); + assert_eq!(gas.spent(), 10); assert_eq!(gas.refunded(), 2); let gas = call_last_frame_return(InstructionResult::Revert, return_gas); assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spend(), 10); + assert_eq!(gas.spent(), 10); assert_eq!(gas.refunded(), 0); } @@ -190,7 +190,7 @@ mod tests { fn test_revert_gas() { let gas = call_last_frame_return(InstructionResult::Revert, Gas::new(90)); assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spend(), 10); + assert_eq!(gas.spent(), 10); assert_eq!(gas.refunded(), 0); } } diff --git a/crates/revm/src/handler/mainnet/post_execution.rs b/crates/revm/src/handler/mainnet/post_execution.rs index 6d70b4fedfc..a0b81a0dc0f 100644 --- a/crates/revm/src/handler/mainnet/post_execution.rs +++ b/crates/revm/src/handler/mainnet/post_execution.rs @@ -42,7 +42,7 @@ pub fn reward_beneficiary( coinbase_account.info.balance = coinbase_account .info .balance - .saturating_add(coinbase_gas_price * U256::from(gas.spend() - gas.refunded() as u64)); + .saturating_add(coinbase_gas_price * U256::from(gas.spent() - gas.refunded() as u64)); Ok(()) } @@ -79,7 +79,7 @@ pub fn output( core::mem::replace(&mut context.evm.error, Ok(()))?; // used gas with refund calculated. let gas_refunded = result.gas().refunded() as u64; - let final_gas_used = result.gas().spend() - gas_refunded; + let final_gas_used = result.gas().spent() - gas_refunded; let output = result.output(); let instruction_result = result.into_interpreter_result(); diff --git a/crates/revm/src/optimism/handler_register.rs b/crates/revm/src/optimism/handler_register.rs index 0bc348dc9e7..fe6ee94cbb0 100644 --- a/crates/revm/src/optimism/handler_register.rs +++ b/crates/revm/src/optimism/handler_register.rs @@ -272,7 +272,7 @@ pub fn reward_beneficiary( .env .block .basefee - .mul(U256::from(gas.spend() - gas.refunded() as u64)); + .mul(U256::from(gas.spent() - gas.refunded() as u64)); } Ok(()) } @@ -410,7 +410,7 @@ mod tests { let gas = call_last_frame_return::(env, InstructionResult::Revert, Gas::new(90)); assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spend(), 10); + assert_eq!(gas.spent(), 10); assert_eq!(gas.refunded(), 0); } @@ -423,7 +423,7 @@ mod tests { let gas = call_last_frame_return::(env, InstructionResult::Stop, Gas::new(90)); assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spend(), 10); + assert_eq!(gas.spent(), 10); assert_eq!(gas.refunded(), 0); } @@ -439,12 +439,12 @@ mod tests { let gas = call_last_frame_return::(env.clone(), InstructionResult::Stop, ret_gas); assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spend(), 10); + assert_eq!(gas.spent(), 10); assert_eq!(gas.refunded(), 2); // min(20, 10/5) let gas = call_last_frame_return::(env, InstructionResult::Revert, ret_gas); assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spend(), 10); + assert_eq!(gas.spent(), 10); assert_eq!(gas.refunded(), 0); } @@ -456,7 +456,7 @@ mod tests { let gas = call_last_frame_return::(env, InstructionResult::Stop, Gas::new(90)); assert_eq!(gas.remaining(), 0); - assert_eq!(gas.spend(), 100); + assert_eq!(gas.spent(), 100); assert_eq!(gas.refunded(), 0); }