Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
feat(interpreter): make most gas cost calculation functions const
  • Loading branch information
DaniPopes committed Mar 28, 2024
commit 607b452d54d52d7d5fa7992373be6e85248bdfcf
131 changes: 74 additions & 57 deletions crates/interpreter/src/gas/calc.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
use revm_primitives::SpecId;

use super::constants::*;
use crate::inner_models::SelfDestructResult;
use crate::primitives::{Address, Spec, SpecId::*, U256};
use crate::primitives::{Address, Spec, SpecId, SpecId::*, U256};
use std::vec::Vec;

/// `const` Option `?`.
macro_rules! tri {
($e:expr) => {
match $e {
Some(v) => v,
None => return None,
}
};
}

/// `const` unwrap.
macro_rules! opt_unwrap {
($e:expr) => {
match $e {
Some(v) => v,
None => panic!("unwrap failed"),
}
};
}

/// `SSTORE` opcode refund calculation.
#[allow(clippy::collapsible_else_if)]
pub fn sstore_refund(spec_id: SpecId, original: U256, current: U256, new: U256) -> i64 {
if spec_id.is_enabled_in(SpecId::ISTANBUL) {
Expand Down Expand Up @@ -55,16 +74,12 @@ pub fn sstore_refund(spec_id: SpecId, original: U256, current: U256, new: U256)
}
}

/// `CREATE2` opcode cost calculation.
#[inline]
pub fn create2_cost(len: usize) -> Option<u64> {
let base = CREATE;
// ceil(len / 32.0)
let len = len as u64;
let sha_addup_base = (len / 32) + u64::from((len % 32) != 0);
let sha_addup = KECCAK256WORD.checked_mul(sha_addup_base)?;
let gas = base.checked_add(sha_addup)?;

Some(gas)
pub const fn create2_cost(len: u64) -> Option<u64> {
let sha_addup_base = len.div_ceil(32);
let sha_addup = tri!(KECCAK256WORD.checked_mul(sha_addup_base));
CREATE.checked_add(sha_addup)
}

#[inline]
Expand All @@ -87,6 +102,7 @@ fn log2floor(value: U256) -> u64 {
l
}

/// `EXP` opcode cost calculation.
#[inline]
pub fn exp_cost(spec_id: SpecId, power: U256) -> Option<u64> {
if power == U256::ZERO {
Expand All @@ -105,19 +121,16 @@ pub fn exp_cost(spec_id: SpecId, power: U256) -> Option<u64> {
}
}

/// `*COPY` opcodes cost calculation.
#[inline]
pub fn verylowcopy_cost(len: u64) -> Option<u64> {
let wordd = len / 32;
let wordr = len % 32;
VERYLOW.checked_add(COPY.checked_mul(if wordr == 0 { wordd } else { wordd + 1 })?)
pub const fn verylowcopy_cost(len: u64) -> Option<u64> {
VERYLOW.checked_add(tri!(cost_per_word(len, COPY)))
}

/// `EXTCODECOPY` opcode cost calculation.
#[inline]
pub fn extcodecopy_cost(spec_id: SpecId, len: u64, is_cold: bool) -> Option<u64> {
let wordd = len / 32;
let wordr = len % 32;

let base_gas: u64 = if spec_id.is_enabled_in(SpecId::BERLIN) {
pub const fn extcodecopy_cost(spec_id: SpecId, len: u64, is_cold: bool) -> Option<u64> {
let base_gas = if spec_id.is_enabled_in(SpecId::BERLIN) {
if is_cold {
COLD_ACCOUNT_ACCESS_COST
} else {
Expand All @@ -128,10 +141,12 @@ pub fn extcodecopy_cost(spec_id: SpecId, len: u64, is_cold: bool) -> Option<u64>
} else {
20
};
base_gas.checked_add(COPY.checked_mul(if wordr == 0 { wordd } else { wordd + 1 })?)
base_gas.checked_add(tri!(cost_per_word(len, COPY)))
}

pub fn account_access_gas(spec_id: SpecId, is_cold: bool) -> u64 {
/// `BALANCE` opcode cost calculation.
#[inline]
pub const fn account_access_gas(spec_id: SpecId, is_cold: bool) -> u64 {
if spec_id.is_enabled_in(SpecId::BERLIN) {
if is_cold {
COLD_ACCOUNT_ACCESS_COST
Expand All @@ -145,15 +160,22 @@ pub fn account_access_gas(spec_id: SpecId, is_cold: bool) -> u64 {
}
}

pub fn log_cost(n: u8, len: u64) -> Option<u64> {
LOG.checked_add(LOGDATA.checked_mul(len)?)?
.checked_add(LOGTOPIC * n as u64)
/// `LOG` opcode cost calculation.
#[inline]
pub const fn log_cost(n: u8, len: u64) -> Option<u64> {
tri!(LOG.checked_add(tri!(LOGDATA.checked_mul(len)))).checked_add(LOGTOPIC * n as u64)
}

/// `KECCAK256` opcode cost calculation.
#[inline]
pub const fn keccak256_cost(len: u64) -> Option<u64> {
KECCAK256.checked_add(tri!(cost_per_word(len, KECCAK256WORD)))
}

pub fn keccak256_cost(len: u64) -> Option<u64> {
let wordd = len / 32;
let wordr = len % 32;
KECCAK256.checked_add(KECCAK256WORD.checked_mul(if wordr == 0 { wordd } else { wordd + 1 })?)
/// Cost for memory length. `ceil(len / 32) * multiple`.
#[inline]
pub const fn cost_per_word(len: u64, multiple: u64) -> Option<u64> {
len.div_ceil(32).checked_mul(multiple)
}

/// EIP-3860: Limit and meter initcode
Expand All @@ -162,14 +184,13 @@ pub fn keccak256_cost(len: u64) -> Option<u64> {
///
/// This cannot overflow as the initcode length is assumed to be checked.
#[inline]
pub fn initcode_cost(len: u64) -> u64 {
let wordd = len / 32;
let wordr = len % 32;
INITCODE_WORD_COST * if wordr == 0 { wordd } else { wordd + 1 }
pub const fn initcode_cost(len: u64) -> u64 {
opt_unwrap!(cost_per_word(len, INITCODE_WORD_COST))
}

/// `SLOAD` opcode cost calculation.
#[inline]
pub fn sload_cost(spec_id: SpecId, is_cold: bool) -> u64 {
pub const fn sload_cost(spec_id: SpecId, is_cold: bool) -> u64 {
if spec_id.is_enabled_in(SpecId::BERLIN) {
if is_cold {
COLD_SLOAD_COST
Expand All @@ -187,7 +208,8 @@ pub fn sload_cost(spec_id: SpecId, is_cold: bool) -> u64 {
}
}

#[allow(clippy::collapsible_else_if)]
/// `SSTORE` opcode cost calculation.
#[inline]
pub fn sstore_cost(
spec_id: SpecId,
original: U256,
Expand Down Expand Up @@ -223,7 +245,7 @@ pub fn sstore_cost(
}

/// EIP-2200: Structured Definitions for Net Gas Metering
#[inline(always)]
#[inline]
fn istanbul_sstore_cost<const SLOAD_GAS: u64, const SSTORE_RESET_GAS: u64>(
original: U256,
current: U256,
Expand All @@ -240,7 +262,8 @@ fn istanbul_sstore_cost<const SLOAD_GAS: u64, const SSTORE_RESET_GAS: u64>(
}
}

/// Frontier sstore cost just had two cases set and reset values
/// Frontier sstore cost just had two cases set and reset values.
#[inline]
fn frontier_sstore_cost(current: U256, new: U256) -> u64 {
if current == U256::ZERO && new != U256::ZERO {
SSTORE_SET
Expand All @@ -249,7 +272,9 @@ fn frontier_sstore_cost(current: U256, new: U256) -> u64 {
}
}

pub fn selfdestruct_cost(spec_id: SpecId, res: SelfDestructResult) -> u64 {
/// `SELFDESTRUCT` opcode cost calculation.
#[inline]
pub const fn selfdestruct_cost(spec_id: SpecId, res: SelfDestructResult) -> u64 {
// EIP-161: State trie clearing (invariant-preserving alternative)
let should_charge_topup = if spec_id.is_enabled_in(SpecId::SPURIOUS_DRAGON) {
res.had_value && !res.target_exists
Expand Down Expand Up @@ -279,7 +304,9 @@ pub fn selfdestruct_cost(spec_id: SpecId, res: SelfDestructResult) -> u64 {
gas
}

pub fn call_gas(spec_id: SpecId, is_cold: bool) -> u64 {
/// Basic `CALL` opcode cost calculation, see [`call_cost`].
#[inline]
pub const fn call_gas(spec_id: SpecId, is_cold: bool) -> u64 {
if spec_id.is_enabled_in(SpecId::BERLIN) {
if is_cold {
COLD_ACCOUNT_ACCESS_COST
Expand All @@ -294,7 +321,9 @@ pub fn call_gas(spec_id: SpecId, is_cold: bool) -> u64 {
}
}

pub fn call_cost(
/// `CALL` opcode cost calculation.
#[inline]
pub const fn call_cost(
spec_id: SpecId,
transfers_value: bool,
is_new: bool,
Expand All @@ -308,20 +337,7 @@ pub fn call_cost(
}

#[inline]
pub fn warm_cold_cost(spec_id: SpecId, is_cold: bool, regular_value: u64) -> u64 {
if spec_id.is_enabled_in(SpecId::BERLIN) {
if is_cold {
COLD_ACCOUNT_ACCESS_COST
} else {
WARM_STORAGE_READ_COST
}
} else {
regular_value
}
}

#[inline]
fn xfer_cost(is_call_or_callcode: bool, transfers_value: bool) -> u64 {
const fn xfer_cost(is_call_or_callcode: bool, transfers_value: bool) -> u64 {
if is_call_or_callcode && transfers_value {
CALLVALUE
} else {
Expand All @@ -330,7 +346,7 @@ fn xfer_cost(is_call_or_callcode: bool, transfers_value: bool) -> u64 {
}

#[inline]
fn new_cost(
const fn new_cost(
spec_id: SpecId,
is_call_or_staticcall: bool,
is_new: bool,
Expand All @@ -348,8 +364,9 @@ fn new_cost(
NEWACCOUNT
}

/// Memory expansion cost calculation.
#[inline]
pub fn memory_gas(a: usize) -> u64 {
pub const fn memory_gas(a: usize) -> u64 {
let a = a as u64;
MEMORY
.saturating_mul(a)
Expand Down
2 changes: 1 addition & 1 deletion crates/interpreter/src/instructions/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ pub fn create<const IS_CREATE2: bool, H: Host, SPEC: Spec>(
// EIP-1014: Skinny CREATE2
let scheme = if IS_CREATE2 {
pop!(interpreter, salt);
gas_or_fail!(interpreter, gas::create2_cost(len));
gas_or_fail!(interpreter, gas::create2_cost(len as u64));
CreateScheme::Create2 { salt }
} else {
gas!(interpreter, gas::CREATE);
Expand Down
2 changes: 1 addition & 1 deletion crates/interpreter/src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ impl Interpreter {
let out_offset = call_outcome.memory_start();
let out_len = call_outcome.memory_length();

self.return_data_buffer = call_outcome.output().to_owned();
self.return_data_buffer.clone_from(call_outcome.output());
let target_len = min(out_len, self.return_data_buffer.len());

match call_outcome.instruction_result() {
Expand Down