Skip to content

chore(l1): fix contract deployment tests from EIP-7002 #2630

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
May 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8df6626
Fix 2 ef tests on LEVM
DiegoCivi Apr 28, 2025
96f578a
Format code
DiegoCivi Apr 28, 2025
3faae2f
Fix 2 ef tests from EIP-7251
DiegoCivi Apr 28, 2025
403ebc5
Merge branch 'main' into fix_eip7002_ef_tests
DiegoCivi Apr 28, 2025
82dcd1c
Remove unwraps and use .get_acount()
DiegoCivi Apr 28, 2025
6fb4f19
Format code
DiegoCivi Apr 28, 2025
b7b445e
Handle revert when executing a system call
DiegoCivi Apr 29, 2025
d684949
Fix EIP-7002 tests on REVM
DiegoCivi Apr 29, 2025
7ba1119
Fix EIP-7251 tests on REVM
DiegoCivi Apr 29, 2025
10ba899
Move repeated code to new function
DiegoCivi Apr 30, 2025
6cd4587
Merge branch 'main' into fix_eip7002_ef_tests
DiegoCivi Apr 30, 2025
7ac4ab7
Use code_hash instead of bytecode
DiegoCivi Apr 30, 2025
88d6054
Add more complete error messages
DiegoCivi Apr 30, 2025
02b6243
Merge branch 'main' into fix_eip7002_ef_tests
DiegoCivi Apr 30, 2025
78fe6ed
Format code
DiegoCivi Apr 30, 2025
061de5b
Merge branch 'fix_eip7002_ef_tests' of github.com:lambdaclass/ethrex …
DiegoCivi Apr 30, 2025
00d57b5
Fix comment typo
DiegoCivi May 7, 2025
86bcf0c
Simplify code check using has_code() method
DiegoCivi May 7, 2025
8ef2f95
Simplify code check using has_code() method on LEVM
DiegoCivi May 7, 2025
2025181
Improve error message
DiegoCivi May 7, 2025
8a09546
Improve access to REVM state
DiegoCivi May 7, 2025
38992c3
Merge branch 'main' into fix_eip7002_ef_tests
DiegoCivi May 7, 2025
333fde3
Merge branch 'main' into fix_eip7002_ef_tests
DiegoCivi May 8, 2025
a92607d
Merge branch 'main' into fix_eip7002_ef_tests
DiegoCivi May 8, 2025
fe4b925
Merge branch 'main' into fix_eip7002_ef_tests
DiegoCivi May 8, 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
24 changes: 6 additions & 18 deletions cmd/ef_tests/blockchain/tests/prague.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,20 @@ use ethrex_vm::EvmEngine;

// TODO: enable these tests once the evm is updated.
#[cfg(not(feature = "levm"))]
const SKIPPED_TESTS_REVM: [&str; 13] = [
const SKIPPED_TESTS_REVM: [&str; 5] = [
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_non_empty_storage[fork_Prague-blockchain_test-zero_nonce]",
"tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py::test_system_contract_deployment[fork_CancunToPragueAtTime15k-blockchain_test-deploy_after_fork-nonzero_balance]",
"tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py::test_system_contract_deployment[fork_CancunToPragueAtTime15k-blockchain_test-deploy_after_fork-zero_balance]",
"tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_out_of_gas-system_contract_0x00000961ef480eb55e80d19ad83579a64c007002]",
"tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_reverts-system_contract_0x00000961ef480eb55e80d19ad83579a64c007002]",
"tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_reaches_gas_limit-system_contract_0x00000961ef480eb55e80d19ad83579a64c007002]",
"tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_throws-system_contract_0x00000961ef480eb55e80d19ad83579a64c007002]",
"tests/prague/eip7251_consolidations/test_contract_deployment.py::test_system_contract_deployment[fork_CancunToPragueAtTime15k-blockchain_test-deploy_after_fork-zero_balance]",
"tests/prague/eip7251_consolidations/test_contract_deployment.py::test_system_contract_deployment[fork_CancunToPragueAtTime15k-blockchain_test-deploy_after_fork-nonzero_balance]",
"tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_reaches_gas_limit-system_contract_0x0000bbddc7ce488642fb579f8b00f3a590007251]",
"tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_out_of_gas-system_contract_0x0000bbddc7ce488642fb579f8b00f3a590007251]",
"tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_throws-system_contract_0x0000bbddc7ce488642fb579f8b00f3a590007251]",
"tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_reverts-system_contract_0x0000bbddc7ce488642fb579f8b00f3a590007251]",
];

#[cfg(feature = "levm")]
const SKIPPED_TESTS_LEVM: [&str; 46] = [
"tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py::test_system_contract_deployment[fork_CancunToPragueAtTime15k-blockchain_test-deploy_after_fork-nonzero_balance]",
"tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py::test_system_contract_deployment[fork_CancunToPragueAtTime15k-blockchain_test-deploy_after_fork-zero_balance]",
"tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_out_of_gas-system_contract_0x00000961ef480eb55e80d19ad83579a64c007002]",
"tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_reverts-system_contract_0x00000961ef480eb55e80d19ad83579a64c007002]",
const SKIPPED_TESTS_LEVM: [&str; 38] = [
"tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_reaches_gas_limit-system_contract_0x00000961ef480eb55e80d19ad83579a64c007002]",
"tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_throws-system_contract_0x00000961ef480eb55e80d19ad83579a64c007002]",
"tests/prague/eip7251_consolidations/test_contract_deployment.py::test_system_contract_deployment[fork_CancunToPragueAtTime15k-blockchain_test-deploy_after_fork-zero_balance]",
"tests/prague/eip7251_consolidations/test_contract_deployment.py::test_system_contract_deployment[fork_CancunToPragueAtTime15k-blockchain_test-deploy_after_fork-nonzero_balance]",
"tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_reaches_gas_limit-system_contract_0x0000bbddc7ce488642fb579f8b00f3a590007251]",
"tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_out_of_gas-system_contract_0x0000bbddc7ce488642fb579f8b00f3a590007251]",
"tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_throws-system_contract_0x0000bbddc7ce488642fb579f8b00f3a590007251]",
"tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_reverts-system_contract_0x0000bbddc7ce488642fb579f8b00f3a590007251]",
"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]",
"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]",
"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]",
Expand Down Expand Up @@ -76,6 +60,10 @@ const SKIPPED_TESTS_LEVM: [&str; 46] = [
//"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_max_depth_call_stack[fork_Prague-blockchain_test]",
//"tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py::test_pointer_contract_pointer_loop[fork_Prague-blockchain_test]",

// NOTE: The following test fails because of an OutOfGas error. This happens because it tests a system call to a contract that has a
// code with a cost of +29 million gas that when is being summed to the 21k base intrinsic gas it goes over the 30 million limit.
// "tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py::test_system_contract_errors[fork_Prague-blockchain_test-system_contract_reaches_gas_limit-system_contract_0x00000961ef480eb55e80d19ad83579a64c007002]",

#[cfg(not(feature = "levm"))]
fn parse_and_execute_with_revm(path: &Path) -> datatest_stable::Result<()> {
parse_and_execute(path, EvmEngine::REVM, Some(&SKIPPED_TESTS_REVM));
Expand Down
61 changes: 36 additions & 25 deletions crates/vm/backends/levm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,37 +303,59 @@ impl LEVM {
pub(crate) fn read_withdrawal_requests(
block_header: &BlockHeader,
db: &mut GeneralizedDatabase,
) -> Option<ExecutionReport> {
) -> Result<ExecutionReport, EvmError> {
let report = generic_system_contract_levm(
block_header,
Bytes::new(),
db,
*WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS,
*SYSTEM_ADDRESS,
)
.ok()?;
)?;

// According to EIP-7002 we need to check if the WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS
// has any code after being deployed. If not, the whole block becomes invalid.
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7002.md
let account = db.get_account(*WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS)?;
if !account.has_code() {
return Err(EvmError::Custom("BlockException.SYSTEM_CONTRACT_EMPTY: WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS has no code after deployment".to_string()));
}

match report.result {
TxResult::Success => Some(report),
_ => None,
TxResult::Success => Ok(report),
// EIP-7002 specifies that a failed system call invalidates the entire block.
TxResult::Revert(vm_error) => Err(EvmError::Custom(format!(
"REVERT when reading withdrawal requests with error: {:?}. According to EIP-7002, the revert of this system call invalidates the block.",
vm_error
))),
}
}
pub(crate) fn dequeue_consolidation_requests(
block_header: &BlockHeader,
db: &mut GeneralizedDatabase,
) -> Option<ExecutionReport> {
) -> Result<ExecutionReport, EvmError> {
let report = generic_system_contract_levm(
block_header,
Bytes::new(),
db,
*CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS,
*SYSTEM_ADDRESS,
)
.ok()?;
)?;

// According to EIP-7251 we need to check if the CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS
// has any code after being deployed. If not, the whole block becomes invalid.
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7251.md
let acc = db.get_account(*CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS)?;
if !acc.has_code() {
return Err(EvmError::Custom("BlockException.SYSTEM_CONTRACT_EMPTY: CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS has no code after deployment".to_string()));
}

match report.result {
TxResult::Success => Some(report),
_ => None,
TxResult::Success => Ok(report),
// EIP-7251 specifies that a failed system call invalidates the entire block.
TxResult::Revert(vm_error) => Err(EvmError::Custom(format!(
"REVERT when dequeuing consolidation requests with error: {:?}. According to EIP-7251, the revert of this system call invalidates the block.",
vm_error
))),
}
}

Expand Down Expand Up @@ -631,21 +653,10 @@ pub fn extract_all_requests_levm(
}
}

let withdrawals_data: Vec<u8> = match LEVM::read_withdrawal_requests(header, db) {
Some(report) => {
// the cache is updated inside the generic_system_call
report.output.into()
}
None => Default::default(),
};

let consolidation_data: Vec<u8> = match LEVM::dequeue_consolidation_requests(header, db) {
Some(report) => {
// the cache is updated inside the generic_system_call
report.output.into()
}
None => Default::default(),
};
let withdrawals_data: Vec<u8> = LEVM::read_withdrawal_requests(header, db)?.output.into();
let consolidation_data: Vec<u8> = LEVM::dequeue_consolidation_requests(header, db)?
.output
.into();

let deposits = Requests::from_deposit_receipts(chain_config.deposit_contract_address, receipts);
let withdrawals = Requests::from_withdrawals_data(withdrawals_data);
Expand Down
91 changes: 73 additions & 18 deletions crates/vm/backends/revm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use ethrex_storage::{error::StoreError, AccountUpdate};

use revm::db::states::bundle_state::BundleRetention;
use revm::db::AccountStatus;
use revm::Database;
use revm::{
db::AccountState as RevmAccountState,
inspectors::TracerEip3155,
Expand Down Expand Up @@ -185,42 +186,96 @@ impl REVM {
)?;
Ok(())
}
fn system_contract_account_info(
addr: Address,
state: &mut EvmState,
) -> Result<revm_primitives::AccountInfo, EvmError> {
let revm_addr = RevmAddress::from_slice(addr.as_bytes());
let account_info = match state {
EvmState::Store(db) => db.basic(revm_addr)?,
EvmState::Execution(cache_db) => cache_db.basic(revm_addr)?,
}
.ok_or(EvmError::DB(StoreError::Custom(
"System contract address was not found after deployment".to_string(),
)))?;
Ok(account_info)
}
pub(crate) fn read_withdrawal_requests(
block_header: &BlockHeader,
state: &mut EvmState,
) -> Option<Vec<u8>> {
) -> Result<Vec<u8>, EvmError> {
let tx_result = generic_system_contract_revm(
block_header,
Bytes::new(),
state,
*WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS,
*SYSTEM_ADDRESS,
)
.ok()?;
)?;

if tx_result.is_success() {
Some(tx_result.output().into())
} else {
None
// According to EIP-7002 we need to check if the WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS
// has any code after being deployed. If not, the whole block becomes invalid.
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7002.md
let account_info =
Self::system_contract_account_info(*WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, state)?;
if account_info.is_empty_code_hash() {
return Err(EvmError::Custom("BlockException.SYSTEM_CONTRACT_EMPTY: WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS has no code after deployment".to_string()));
}

match tx_result {
ExecutionResult::Success {
gas_used: _,
gas_refunded: _,
logs: _,
output,
} => Ok(output.into()),
// EIP-7002 specifies that a failed system call invalidates the entire block.
ExecutionResult::Halt { reason, gas_used } => {
let err_str = format!("Transaction HALT when calling WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS with reason: {reason} and with used gas: {gas_used}");
Err(EvmError::Custom(err_str))
}
ExecutionResult::Revert { gas_used, output } => {
let err_str = format!("Transaction REVERT when calling WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS with output: {:?} and with used gas: {gas_used}", output);
Err(EvmError::Custom(err_str))
}
}
}
pub(crate) fn dequeue_consolidation_requests(
block_header: &BlockHeader,
state: &mut EvmState,
) -> Option<Vec<u8>> {
) -> Result<Vec<u8>, EvmError> {
let tx_result = generic_system_contract_revm(
block_header,
Bytes::new(),
state,
*CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS,
*SYSTEM_ADDRESS,
)
.ok()?;
)?;

// According to EIP-7251 we need to check if the CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS
// has any code after being deployed. If not, the whole block becomes invalid.
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7251.md
let account_info =
Self::system_contract_account_info(*CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS, state)?;
if account_info.is_empty_code_hash() {
return Err(EvmError::Custom("BlockException.SYSTEM_CONTRACT_EMPTY: CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS has no code after deployment".to_string()));
}

if tx_result.is_success() {
Some(tx_result.output().into())
} else {
None
match tx_result {
ExecutionResult::Success {
gas_used: _,
gas_refunded: _,
logs: _,
output,
} => Ok(output.into()),
// EIP-7251 specifies that a failed system call invalidates the entire block.
ExecutionResult::Halt { reason, gas_used } => {
let err_str = format!("Transaction HALT when calling CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS with reason: {reason} and with used gas: {gas_used}");
Err(EvmError::Custom(err_str))
}
ExecutionResult::Revert { gas_used, output } => {
let err_str = format!("Transaction REVERT when calling CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS with output: {:?} and with used gas: {gas_used}", output);
Err(EvmError::Custom(err_str))
}
}
}

Expand Down Expand Up @@ -693,11 +748,11 @@ pub fn extract_all_requests(
}

let deposits = Requests::from_deposit_receipts(config.deposit_contract_address, receipts);
let withdrawals_data = REVM::read_withdrawal_requests(header, state);
let consolidation_data = REVM::dequeue_consolidation_requests(header, state);
let withdrawals_data = REVM::read_withdrawal_requests(header, state)?;
let consolidation_data = REVM::dequeue_consolidation_requests(header, state)?;

let withdrawals = Requests::from_withdrawals_data(withdrawals_data.unwrap_or_default());
let consolidation = Requests::from_consolidation_data(consolidation_data.unwrap_or_default());
let withdrawals = Requests::from_withdrawals_data(withdrawals_data);
let consolidation = Requests::from_consolidation_data(consolidation_data);

Ok(vec![deposits, withdrawals, consolidation])
}