diff --git a/src/handler.rs b/src/handler.rs index 92233fc..11ee85d 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -125,7 +125,10 @@ where is_nonce_check_disabled, )?; - // only check balance if l1 message and Spec is EUCLID. + // Note: we skip the balance check at pre-execution level if the transaction is a + // L1 message and Euclid is enabled. This means the L1 message will reach execution + // stage in revm and revert with `OutOfFunds` in the first frame, but still be included + // in the block. let skip_balance_check = tx.is_l1_msg() && spec.is_enabled_in(ScrollSpecId::EUCLID); if !skip_balance_check { let max_balance_spending = tx.max_balance_spending()?; diff --git a/src/tests/l1_message.rs b/src/tests/l1_message.rs index 15aced6..392759c 100644 --- a/src/tests/l1_message.rs +++ b/src/tests/l1_message.rs @@ -7,10 +7,15 @@ use crate::{ }; use std::boxed::Box; +use crate::test_utils::MIN_TRANSACTION_COST; use revm::{ - context::{result::EVMError, ContextTr, JournalTr}, + context::{ + result::{EVMError, ExecutionResult, HaltReason, ResultAndState}, + ContextTr, JournalTr, + }, handler::{EthFrame, EvmTr, FrameResult, Handler}, interpreter::{CallOutcome, Gas, InstructionResult, InterpreterResult}, + ExecuteEvm, }; use revm_primitives::U256; @@ -120,3 +125,26 @@ fn test_reward_beneficiary_l1_message() -> Result<(), Box Result<(), Box> { + let ctx = context().modify_tx_chained(|tx| { + tx.base.tx_type = L1_MESSAGE_TYPE; + tx.base.value = U256::ONE; + }); + let tx = ctx.tx.clone(); + let mut evm = ctx.build_scroll(); + + let ResultAndState { result, .. } = evm.transact(tx)?; + + // L1 message should pass pre-execution but revert with `OutOfFunds`. + assert_eq!( + result, + ExecutionResult::Halt { + gas_used: MIN_TRANSACTION_COST.to(), + reason: HaltReason::OutOfFunds + } + ); + + Ok(()) +}