Skip to content

Commit 9ba8270

Browse files
authored
fix(levm): fix last blockchain tests for LEVM (#2842)
**Motivation** - Fix remaining blockchain tests for Prague with LEVM. **Description** - Precompiles shouldn't be executed in case they are delegation target of the same transaction in which they are being called. - It also fixes a problem in the transfer of value in CALL. (It just moves the place where the value transfer is performed) After this there are no more `blockchain` tests we need to fix. <!-- Link to issues: Resolves #111, Resolves #222 --> Co-authored-by: @DiegoCivi
1 parent 2fcf668 commit 9ba8270

File tree

4 files changed

+62
-87
lines changed

4 files changed

+62
-87
lines changed

cmd/ef_tests/blockchain/tests/prague.rs

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3,64 +3,15 @@ use std::path::Path;
33
use ef_tests_blockchain::test_runner::parse_and_execute;
44
use ethrex_vm::EvmEngine;
55

6-
// TODO: enable these tests once the evm is updated.
7-
#[cfg(not(feature = "levm"))]
8-
const SKIPPED_TESTS_REVM: [&str; 1] = [
9-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_non_empty_storage[fork_Prague-blockchain_test-zero_nonce]",
10-
];
11-
12-
#[cfg(feature = "levm")]
13-
const SKIPPED_TESTS_LEVM: [&str; 34] = [
14-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x0000000000000000000000000000000000000006-blockchain_test_from_state_test]",
15-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x0000000000000000000000000000000000000011-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
16-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x0000000000000000000000000000000000000009-blockchain_test_from_state_test]",
17-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x000000000000000000000000000000000000000b-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
18-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x000000000000000000000000000000000000000e-blockchain_test_from_state_test]",
19-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x0000000000000000000000000000000000000004-blockchain_test_from_state_test]",
20-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x0000000000000000000000000000000000000009-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
21-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x000000000000000000000000000000000000000c-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
22-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x000000000000000000000000000000000000000c-blockchain_test_from_state_test]",
23-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x000000000000000000000000000000000000000a-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
24-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x0000000000000000000000000000000000000008-blockchain_test_from_state_test]",
25-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x0000000000000000000000000000000000000001-blockchain_test_from_state_test]",
26-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x0000000000000000000000000000000000000006-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
27-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x000000000000000000000000000000000000000f-blockchain_test_from_state_test]",
28-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x0000000000000000000000000000000000000010-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
29-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x000000000000000000000000000000000000000f-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
30-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x0000000000000000000000000000000000000011-blockchain_test_from_state_test]",
31-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x0000000000000000000000000000000000000002-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
32-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x000000000000000000000000000000000000000b-blockchain_test_from_state_test]",
33-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x000000000000000000000000000000000000000e-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
34-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x0000000000000000000000000000000000000005-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
35-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x000000000000000000000000000000000000000d-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
36-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x0000000000000000000000000000000000000001-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
37-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x0000000000000000000000000000000000000004-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
38-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x0000000000000000000000000000000000000007-blockchain_test_from_state_test]",
39-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x0000000000000000000000000000000000000003-blockchain_test_from_state_test]",
40-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x0000000000000000000000000000000000000005-blockchain_test_from_state_test]",
41-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x0000000000000000000000000000000000000010-blockchain_test_from_state_test]",
42-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x0000000000000000000000000000000000000007-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
43-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x000000000000000000000000000000000000000d-blockchain_test_from_state_test]",
44-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x0000000000000000000000000000000000000008-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
45-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x0000000000000000000000000000000000000002-blockchain_test_from_state_test]",
46-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile_not_enough_gas_for_precompile_execution[fork_Prague-precompile_0x000000000000000000000000000000000000000a-blockchain_test_from_state_test]",
47-
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_precompile[fork_Prague-precompile_0x0000000000000000000000000000000000000003-call_opcode_CALL-evm_code_type_LEGACY-blockchain_test_from_state_test]",
48-
];
49-
50-
// NOTE: These 3 tests fail on LEVM with a stack overflow if we do not increase the stack size by using RUST_MIN_STACK=11000000
51-
//"tests/prague/eip6110_deposits/test_deposits.py::test_deposit[fork_Prague-blockchain_test-single_deposit_from_contract_call_high_depth]",
52-
//"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_max_depth_call_stack[fork_Prague-blockchain_test]",
53-
//"tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py::test_pointer_contract_pointer_loop[fork_Prague-blockchain_test]",
54-
556
#[cfg(not(feature = "levm"))]
567
fn parse_and_execute_with_revm(path: &Path) -> datatest_stable::Result<()> {
57-
parse_and_execute(path, EvmEngine::REVM, Some(&SKIPPED_TESTS_REVM));
8+
parse_and_execute(path, EvmEngine::REVM, None);
589
Ok(())
5910
}
6011

6112
#[cfg(feature = "levm")]
6213
fn parse_and_execute_with_levm(path: &Path) -> datatest_stable::Result<()> {
63-
parse_and_execute(path, EvmEngine::LEVM, Some(&SKIPPED_TESTS_LEVM));
14+
parse_and_execute(path, EvmEngine::LEVM, None);
6415
Ok(())
6516
}
6617

crates/vm/levm/src/opcode_handlers/system.rs

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -767,40 +767,41 @@ impl<'a> VM<'a> {
767767
calldata
768768
};
769769

770-
let new_depth = {
771-
let current_call_frame = self.current_call_frame_mut()?;
772-
773-
// 2. Validate max depth has not been reached yet.
774-
let new_depth = current_call_frame
775-
.depth
776-
.checked_add(1)
777-
.ok_or(InternalError::ArithmeticOperationOverflow)?;
770+
// 2. Validate max depth has not been reached yet.
771+
let new_depth = self
772+
.current_call_frame()?
773+
.depth
774+
.checked_add(1)
775+
.ok_or(InternalError::ArithmeticOperationOverflow)?;
778776

779-
if new_depth > 1024 {
780-
current_call_frame.gas_used = current_call_frame
781-
.gas_used
782-
.checked_sub(gas_limit)
783-
.ok_or(InternalError::GasOverflow)?;
784-
current_call_frame.stack.push(REVERT_FOR_CALL)?;
785-
return Ok(OpcodeResult::Continue { pc_increment: 1 });
786-
}
777+
if new_depth > 1024 {
778+
self.current_call_frame_mut()?.gas_used = self
779+
.current_call_frame()?
780+
.gas_used
781+
.checked_sub(gas_limit)
782+
.ok_or(InternalError::GasOverflow)?;
783+
self.current_call_frame_mut()?.stack.push(REVERT_FOR_CALL)?;
784+
return Ok(OpcodeResult::Continue { pc_increment: 1 });
785+
}
787786

788-
if bytecode.is_empty() && is_delegation {
789-
current_call_frame.gas_used = current_call_frame
790-
.gas_used
791-
.checked_sub(gas_limit)
792-
.ok_or(InternalError::GasOverflow)?;
793-
current_call_frame.stack.push(SUCCESS_FOR_CALL)?;
794-
return Ok(OpcodeResult::Continue { pc_increment: 1 });
795-
}
796-
new_depth
797-
};
798787
// Transfer value from caller to callee.
799788
if should_transfer_value {
800789
self.decrease_account_balance(msg_sender, value)?;
801790
self.increase_account_balance(to, value)?;
802791
}
803792

793+
if bytecode.is_empty() && is_delegation {
794+
self.current_call_frame_mut()?.gas_used = self
795+
.current_call_frame()?
796+
.gas_used
797+
.checked_sub(gas_limit)
798+
.ok_or(InternalError::GasOverflow)?;
799+
self.current_call_frame_mut()?
800+
.stack
801+
.push(SUCCESS_FOR_CALL)?;
802+
return Ok(OpcodeResult::Continue { pc_increment: 1 });
803+
}
804+
804805
let new_call_frame = CallFrame::new(
805806
msg_sender,
806807
to,

crates/vm/levm/src/utils.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,4 +707,11 @@ impl<'a> VM<'a> {
707707

708708
Ok((callee, code))
709709
}
710+
711+
/// Checks if an address is delegation target in current transaction.
712+
pub fn is_delegation_target(&self, address: Address) -> bool {
713+
self.tx.authorization_list().as_ref().map_or(false, |list| {
714+
list.iter().any(|item| item.address == address)
715+
})
716+
}
710717
}

crates/vm/levm/src/vm.rs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ use crate::{
22
call_frame::CallFrame,
33
db::gen_db::GeneralizedDatabase,
44
environment::Environment,
5-
errors::{ExecutionReport, OpcodeResult, VMError},
5+
errors::{ExecutionReport, OpcodeResult, PrecompileError, VMError},
66
hooks::hook::Hook,
77
precompiles::execute_precompile,
88
TransientStorage,
99
};
10+
use bytes::Bytes;
1011
use ethrex_common::{
1112
types::{Transaction, TxKind},
1213
Address, H256, U256,
@@ -145,15 +146,30 @@ impl<'a> VM<'a> {
145146
}
146147

147148
pub fn execute_precompile(&mut self) -> Result<ExecutionReport, VMError> {
148-
let callframe = self.current_call_frame_mut()?;
149-
150-
let precompile_address = callframe.code_address;
151-
let calldata = &callframe.calldata;
152-
let gas_used = &mut callframe.gas_used;
153-
let gas_limit = callframe.gas_limit;
154-
155-
let precompile_result =
156-
execute_precompile(precompile_address, calldata, gas_used, gas_limit);
149+
let precompile_address = self.current_call_frame()?.code_address;
150+
151+
let precompile_result = match self.is_delegation_target(precompile_address) {
152+
// Avoid executing precompile if it is target of a delegation in EIP-7702 transaction.
153+
true => {
154+
let gas_limit = self.current_call_frame()?.gas_limit;
155+
if gas_limit == 0 {
156+
// `pointer_to_precompile.json` tests that it should fail in a call with zero gas limit.
157+
Err(VMError::PrecompileError(PrecompileError::NotEnoughGas))
158+
} else {
159+
Ok(Bytes::new())
160+
}
161+
}
162+
// Otherwise, execute precompile
163+
false => {
164+
let callframe = self.current_call_frame_mut()?;
165+
execute_precompile(
166+
precompile_address,
167+
&callframe.calldata,
168+
&mut callframe.gas_used,
169+
callframe.gas_limit,
170+
)
171+
}
172+
};
157173

158174
let report = self.handle_precompile_result(precompile_result)?;
159175

0 commit comments

Comments
 (0)