Skip to content
Closed
Changes from all commits
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
92 changes: 92 additions & 0 deletions crates/evm2/src/evm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,11 @@ impl<'a, T: EvmTypes> Evm<'a, T> {
};
message.destination = Self::derive_create_address(&bytecode, message, nonce);
}
if !is_create && let Err(stop) = self.preflight_first_frame_call_runtime_gas(message) {
let mut result = Self::error_message_result(stop, message.gas_limit, message.reservoir);
result.gas.settle_gas(result.stop);
return result;
}

let mut top_frame: Option<Box<Interpreter<'frame, 'a, T>>> = None;
let frame = match self.current_frame {
Expand Down Expand Up @@ -1164,6 +1169,27 @@ impl<'a, T: EvmTypes> Evm<'a, T> {
}
}

fn preflight_first_frame_call_runtime_gas(
&mut self,
message: &Message<T>,
) -> Result<(), InstrStop> {
if message.depth != 0 || !self.feature(EvmFeatures::EIP2780) {
return Ok(());
}

let checkpoint = self.state.checkpoint();
let (regular, state) = self.eip2780_call_charges(message);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah this is not correct, and needs changing. eip2780_call_charges needs to take into account gas limit. and checkpoint creation is in wrong place. If eip2780 checks fail eip7702 delegations need reverting.

let mut gas =
GasTracker::new_with_regular_gas_and_reservoir(message.gas_limit, message.reservoir);
let result = if gas.spend(regular).is_err() || gas.spend_state(state).is_err() {
Err(InstrStop::OutOfGas)
} else {
Ok(())
};
self.state.rollback(checkpoint, self.features);
result
}

#[inline(never)]
fn create_message_account(&mut self, message: &Message<T>) -> Result<(), InstrStop> {
self.state
Expand Down Expand Up @@ -3170,6 +3196,72 @@ mod tests {
);
}

#[test]
fn amsterdam_runtime_oog_call_value_is_not_inspected() {
#[derive(Default)]
struct RuntimeOogInspector {
calls: usize,
call_ends: usize,
logs: usize,
}

impl<T: EvmTypesHost> Inspector<T> for RuntimeOogInspector {
fn call(
&mut self,
_interp: &mut Interpreter<'_, '_, T>,
_message: &mut Message<T>,
) -> Option<MessageResult<T>> {
self.calls += 1;
None
}

fn call_end(
&mut self,
_interp: &mut Interpreter<'_, '_, T>,
_message: &Message<T>,
_result: &mut MessageResult<T>,
) {
self.call_ends += 1;
}

fn log(&mut self, _log: &Log, _host: &mut T::Host<'_>) {
self.logs += 1;
}
}

let caller = Address::from([0x01; 20]);
let target = Address::from([0x02; 20]);
let mut database = InMemoryDB::default();
database.insert_account_info(&caller, AccountInfo::default().with_balance(U256::from(10)));
let mut evm = Evm::<BaseEvmTypes>::new(
SpecId::AMSTERDAM,
BlockEnv::default(),
TxRegistry::new(),
database,
Precompiles::base(SpecId::AMSTERDAM),
);
evm.set_inspector(RuntimeOogInspector::default());
let mut message = Message {
kind: MessageKind::Call,
destination: target,
code_address: target,
caller,
value: U256::from(7),
gas_limit: 23_204,
..Message::default()
};

let result =
Host::execute_message(&mut evm, &TxEnv::default(), Bytecode::default(), &mut message);
let inspector = evm.clear_inspector_as::<RuntimeOogInspector>().unwrap();

assert_eq!(result.stop, InstrStop::OutOfGas);
assert_eq!(inspector.calls, 0);
assert_eq!(inspector.call_ends, 0);
assert_eq!(inspector.logs, 0);
assert!(evm.logs().is_empty());
}

#[test]
fn amsterdam_call_value_emits_eip7708_log() {
let caller = Address::from([0x01; 20]);
Expand Down