Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
da31f27
dyn gas table
rakita Oct 23, 2025
479c9dc
continuation of work
rakita Oct 25, 2025
8e5b4fe
rename to GasParams
rakita Oct 27, 2025
0eaacda
gas params
rakita Oct 28, 2025
fbed8f4
sstore_dyn and sstore refund
rakita Oct 28, 2025
470192d
continuation, first test passing
rakita Oct 28, 2025
54f11f1
cleanup prints
rakita Oct 28, 2025
ab5b80d
fix selfdestruct
rakita Oct 28, 2025
d594d7f
run-tests keep-going, fixes to pass tests
rakita Oct 30, 2025
ee1073e
rename to gas params, sstore/call fixes
rakita Oct 30, 2025
a161465
fix balance
rakita Oct 31, 2025
9184127
Merge remote-tracking branch 'origin/main' into rakita/gas-params
rakita Nov 12, 2025
d2aee56
cache on spec change
rakita Nov 13, 2025
f9097b5
use instruction gas params
rakita Nov 13, 2025
6cdad9a
fix tests
rakita Nov 13, 2025
3d6e8a8
fix tests
rakita Nov 13, 2025
f74afcb
fix tests
rakita Nov 13, 2025
ca2bb6b
fix tests
rakita Nov 13, 2025
2da26ed
fix doc
rakita Nov 13, 2025
e5f12bf
fmt
rakita Nov 13, 2025
697e1d1
cleanup
rakita Nov 13, 2025
89c589e
Merge remote-tracking branch 'origin/main' into rakita/gas-params
rakita Nov 14, 2025
46f3226
Merge remote-tracking branch 'origin/main' into gasparams
rakita Nov 17, 2025
fdf606d
cleanup
rakita Nov 17, 2025
42fdec6
move first values to table
rakita Nov 18, 2025
ab210c0
cleanup
rakita Nov 18, 2025
b495901
Apply suggestion from @rakita
rakita Nov 18, 2025
dbfd6e9
Apply suggestions from code review
rakita Nov 18, 2025
ce4f3e7
Apply suggestion from @rakita
rakita Nov 18, 2025
6e31ece
Apply suggestion from @rakita
rakita Nov 18, 2025
403f28f
Add GasId struct
rakita Nov 18, 2025
563c3bd
nits
rakita Nov 19, 2025
e6d9b74
copilot nits
rakita Nov 19, 2025
d54bcdd
Merge remote-tracking branch 'origin/main' into gasparams
rakita Dec 9, 2025
0ee23df
Merge remote-tracking branch 'origin/main' into gasparam
rakita Dec 9, 2025
53141bd
nit, use resize_memory macro in place of fn
rakita Dec 10, 2025
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
12 changes: 12 additions & 0 deletions crates/context/interface/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,18 @@ impl SStoreResult {
self.new_value.const_eq(&self.present_value)
}

/// Returns `true` if the new values changes the present value.
#[inline]
pub const fn new_values_changes_present(&self) -> bool {
!self.is_new_eq_present()
}

/// Returns `true` if the original value is zero and the new value is not zero.
#[inline]
pub const fn have_changed_from_zero(&self) -> bool {
self.is_original_zero() && !self.is_new_zero()
}

/// Returns `true` if the original value is equal to the present value.
#[inline]
pub const fn is_original_eq_present(&self) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion crates/context/src/journal/inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
address: Address,
target: Address,
skip_cold_load: bool,
) -> Result<StateLoad<SelfDestructResult>, JournalLoadError<<DB as Database>::Error>> {
) -> Result<StateLoad<SelfDestructResult>, JournalLoadError<DB::Error>> {
let spec = self.spec;
let account_load = self.load_account_optional(db, target, false, skip_cold_load)?;
let is_cold = account_load.is_cold;
Expand Down
8 changes: 7 additions & 1 deletion crates/handler/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,13 @@ where

let ctx = &mut self.ctx;
let precompiles = &mut self.precompiles;
let res = Self::Frame::init_with_context(new_frame, ctx, precompiles, frame_input)?;
let res = Self::Frame::init_with_context(
new_frame,
ctx,
precompiles,
frame_input,
self.instruction.gas_params(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can gas_params not be part of the Context?

this should allow us to avoid any changes to InstructionProvider and to the frame init logic which now propagate the GasParams quite deeply just to set the interpreter field while this is technically an externally provided context

it would also only retain the actual dynamic runtime data in Interpreter type

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this also makes me wonder if GasParams could be entirely hidden inside of the InstructionProvider? so that I just do something like EthInstructions::new(gas_params) and it produces an instruction table that uses my gas params?

)?;

Ok(res.map_frame(|token| {
if is_first_init {
Expand Down
19 changes: 15 additions & 4 deletions crates/handler/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use context_interface::{
use core::cmp::min;
use derive_where::derive_where;
use interpreter::{
gas,
gas::{self, params::GasParams},
interpreter::{EthInterpreter, ExtBytecode},
interpreter_action::FrameInit,
interpreter_types::ReturnData,
Expand Down Expand Up @@ -101,6 +101,7 @@ pub type ContextTrDbError<CTX> = <<CTX as ContextTr>::Db as Database>::Error;
impl EthFrame<EthInterpreter> {
/// Clear and initialize a frame.
#[allow(clippy::too_many_arguments)]
#[inline(always)]
pub fn clear(
&mut self,
data: FrameData,
Expand All @@ -113,6 +114,7 @@ impl EthFrame<EthInterpreter> {
spec_id: SpecId,
gas_limit: u64,
checkpoint: JournalCheckpoint,
gas_params: GasParams,
) {
let Self {
data: data_ref,
Expand All @@ -126,7 +128,9 @@ impl EthFrame<EthInterpreter> {
*input_ref = input;
*depth_ref = depth;
*is_finished_ref = false;
interpreter.clear(memory, bytecode, inputs, is_static, spec_id, gas_limit);
interpreter.clear(
memory, bytecode, inputs, is_static, spec_id, gas_limit, gas_params,
);
*checkpoint_ref = checkpoint;
}

Expand All @@ -143,6 +147,7 @@ impl EthFrame<EthInterpreter> {
depth: usize,
memory: SharedMemory,
inputs: Box<CallInputs>,
gas_params: GasParams,
) -> Result<ItemOrResult<FrameToken, FrameResult>, ERROR> {
let gas = Gas::new(inputs.gas_limit);
let return_result = |instruction_result: InstructionResult| {
Expand Down Expand Up @@ -242,6 +247,7 @@ impl EthFrame<EthInterpreter> {
ctx.cfg().spec().into(),
gas_limit,
checkpoint,
gas_params,
);
Ok(ItemOrResult::Item(this.consume()))
}
Expand All @@ -257,6 +263,7 @@ impl EthFrame<EthInterpreter> {
depth: usize,
memory: SharedMemory,
inputs: Box<CreateInputs>,
gas_params: GasParams,
) -> Result<ItemOrResult<FrameToken, FrameResult>, ERROR> {
let spec = context.cfg().spec().into();
let return_error = |e| {
Expand Down Expand Up @@ -343,6 +350,7 @@ impl EthFrame<EthInterpreter> {
spec,
gas_limit,
checkpoint,
gas_params,
);
Ok(ItemOrResult::Item(this.consume()))
}
Expand All @@ -356,6 +364,7 @@ impl EthFrame<EthInterpreter> {
ctx: &mut CTX,
precompiles: &mut PRECOMPILES,
frame_init: FrameInit,
gas_params: GasParams,
) -> Result<
ItemOrResult<FrameToken, FrameResult>,
ContextError<<<CTX as ContextTr>::Db as Database>::Error>,
Expand All @@ -369,9 +378,11 @@ impl EthFrame<EthInterpreter> {

match frame_input {
FrameInput::Call(inputs) => {
Self::make_call_frame(this, ctx, precompiles, depth, memory, inputs)
Self::make_call_frame(this, ctx, precompiles, depth, memory, inputs, gas_params)
}
FrameInput::Create(inputs) => {
Self::make_create_frame(this, ctx, depth, memory, inputs, gas_params)
}
FrameInput::Create(inputs) => Self::make_create_frame(this, ctx, depth, memory, inputs),
FrameInput::Empty => unreachable!(),
}
}
Expand Down
13 changes: 13 additions & 0 deletions crates/handler/src/handler.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::instructions::InstructionProvider;
use crate::{
evm::FrameTr,
execution, post_execution,
Expand Down Expand Up @@ -98,13 +99,23 @@ pub trait Handler {
&mut self,
evm: &mut Self::Evm,
) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
self.configure(evm);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will this not work properly now for any impl overriding this trait? i don't think this is acceptable and we need to either hide this deeper or make it so this change is obvious from compilation issues after the bump

// Run inner handler and catch all errors to handle cleanup.
match self.run_without_catch_error(evm) {
Ok(output) => Ok(output),
Err(e) => self.catch_error(evm, e),
}
}

/// Configure the handler:
/// * Set Instruction gas table to the spec id.
#[inline]
fn configure(&mut self, evm: &mut Self::Evm) {
let spec_id = evm.ctx().cfg().spec().into();
// sets static gas depending on the spec id.
evm.ctx_instructions().1.set_spec(spec_id);
}

/// Runs the system call.
///
/// System call is a special transaction where caller is a [`crate::SYSTEM_ADDRESS`]
Expand All @@ -126,6 +137,8 @@ pub trait Handler {
) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
// dummy values that are not used.
let init_and_floor_gas = InitialAndFloorGas::new(0, 0);
// configure the evm for system call.
self.configure(evm);
// call execution and than output.
match self
.execution(evm, &init_and_floor_gas)
Expand Down
47 changes: 43 additions & 4 deletions crates/handler/src/instructions.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use auto_impl::auto_impl;
use interpreter::{
instructions::{instruction_table, InstructionTable},
gas::params::GasParams,
instructions::{instruction_table_gas_changes_spec, InstructionTable},
Host, Instruction, InterpreterTypes,
};
use primitives::hardfork::SpecId;
use std::boxed::Box;

/// Stores instructions for EVM.
#[auto_impl(&, Arc, Rc)]
#[auto_impl(&mut, Box)]
pub trait InstructionProvider {
/// Context type.
type Context;
Expand All @@ -15,13 +17,23 @@ pub trait InstructionProvider {

/// Returns the instruction table that is used by EvmTr to execute instructions.
fn instruction_table(&self) -> &InstructionTable<Self::InterpreterTypes, Self::Context>;

/// Returns the gas params that is used by EvmTr to execute instructions.
fn gas_params(&self) -> GasParams;

/// Sets the spec. Return true if the spec was changed.
fn set_spec(&mut self, spec: SpecId) -> bool;
}

/// Ethereum instruction contains list of mainnet instructions that is used for Interpreter execution.
#[derive(Debug)]
pub struct EthInstructions<WIRE: InterpreterTypes, HOST: ?Sized> {
/// Table containing instruction implementations indexed by opcode.
pub instruction_table: Box<InstructionTable<WIRE, HOST>>,
/// Gas params that sets gas costs for instructions.
pub gas_params: GasParams,
/// Spec that is used to set gas costs for instructions.
pub spec: SpecId,
}

impl<WIRE, HOST: Host + ?Sized> Clone for EthInstructions<WIRE, HOST>
Expand All @@ -31,6 +43,8 @@ where
fn clone(&self) -> Self {
Self {
instruction_table: self.instruction_table.clone(),
gas_params: self.gas_params.clone(),
spec: self.spec,
}
}
}
Expand All @@ -42,14 +56,25 @@ where
{
/// Returns `EthInstructions` with mainnet spec.
pub fn new_mainnet() -> Self {
Self::new(instruction_table::<WIRE, HOST>())
let spec = SpecId::default();
Self::new(
instruction_table_gas_changes_spec(spec),
GasParams::new_spec(spec),
spec,
)
}

/// Returns a new instance of `EthInstructions` with custom instruction table.
#[inline]
pub fn new(base_table: InstructionTable<WIRE, HOST>) -> Self {
pub fn new(
base_table: InstructionTable<WIRE, HOST>,
gas_params: GasParams,
spec: SpecId,
) -> Self {
Self {
instruction_table: Box::new(base_table),
gas_params,
spec,
}
}

Expand All @@ -71,6 +96,20 @@ where
fn instruction_table(&self) -> &InstructionTable<Self::InterpreterTypes, Self::Context> {
&self.instruction_table
}

fn gas_params(&self) -> GasParams {
self.gas_params.clone()
}

fn set_spec(&mut self, spec: SpecId) -> bool {
if spec == self.spec {
return false;
}
self.instruction_table = Box::new(instruction_table_gas_changes_spec(spec));
self.gas_params = GasParams::new_spec(spec);

true
}
}

impl<WIRE, HOST> Default for EthInstructions<WIRE, HOST>
Expand Down
3 changes: 3 additions & 0 deletions crates/inspector/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ where
&mut self,
evm: &mut Self::Evm,
) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
self.configure(evm);
match self.inspect_run_without_catch_error(evm) {
Ok(output) => Ok(output),
Err(e) => self.catch_error(evm, e),
Expand Down Expand Up @@ -136,6 +137,8 @@ where
) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
// dummy values that are not used.
let init_and_floor_gas = InitialAndFloorGas::new(0, 0);
// configure
self.configure(evm);
// call execution with inspection and then output.
match self
.inspect_execution(evm, &init_and_floor_gas)
Expand Down
25 changes: 18 additions & 7 deletions crates/interpreter/src/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

mod calc;
mod constants;
pub mod params;

pub use calc::*;
pub use constants::*;
Expand Down Expand Up @@ -91,11 +92,6 @@ impl Gas {
self.remaining
}

/// Return remaining gas after subtracting 63/64 parts.
pub const fn remaining_63_of_64_parts(&self) -> u64 {
self.remaining - self.remaining / 64
}

/// Erases a gas cost from the totals.
#[inline]
pub fn erase_cost(&mut self, returned: u64) {
Expand Down Expand Up @@ -199,15 +195,30 @@ impl MemoryGas {
}
}

/// Sets the number of words and the expansion cost.
///
/// Returns the difference between the new and old expansion cost.
#[inline]
pub fn set_words_num(&mut self, words_num: usize, mut expansion_cost: u64) -> Option<u64> {
self.words_num = words_num;
core::mem::swap(&mut self.expansion_cost, &mut expansion_cost);
self.expansion_cost.checked_sub(expansion_cost)
}

/// Records a new memory length and calculates additional cost if memory is expanded.
/// Returns the additional gas cost required, or None if no expansion is needed.
#[inline]
pub fn record_new_len(&mut self, new_num: usize) -> Option<u64> {
pub fn record_new_len(
&mut self,
new_num: usize,
linear_cost: u64,
quadratic_cost: u64,
) -> Option<u64> {
if new_num <= self.words_num {
return None;
}
self.words_num = new_num;
let mut cost = crate::gas::calc::memory_gas(new_num);
let mut cost = crate::gas::calc::memory_gas(new_num, linear_cost, quadratic_cost);
core::mem::swap(&mut self.expansion_cost, &mut cost);
// Safe to subtract because we know that new_len > length
// Notice the swap above.
Expand Down
Loading
Loading