Skip to content
Merged
Show file tree
Hide file tree
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
12 changes: 10 additions & 2 deletions src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ where
#[inline]
fn pre_execution(&self, evm: &mut Self::Evm) -> Result<u64, Self::Error> {
// only load the L1BlockInfo for txs that are not l1 messages.
if !evm.ctx().tx().is_l1_msg() {
if !evm.ctx().tx().is_l1_msg() && !evm.ctx().tx().is_system_tx() {
let spec = evm.ctx().cfg().spec();
let l1_block_info = L1BlockInfo::try_fetch(&mut evm.ctx().db(), spec)?;
*evm.ctx().chain() = l1_block_info;
Expand All @@ -84,16 +84,21 @@ where
let ctx = evm.ctx();
let caller = ctx.tx().caller();
let is_l1_msg = ctx.tx().is_l1_msg();
let is_system_tx = ctx.tx().is_system_tx();
let kind = ctx.tx().kind();
let spec = ctx.cfg().spec();
let is_eip3607_disabled = ctx.cfg().is_eip3607_disabled();
let is_nonce_check_disabled = ctx.cfg().is_nonce_check_disabled();

// execute normal checks and transaction processing logic for non-l1-msgs
if !is_l1_msg {
// We deduct caller max balance after minting and before deducing the
// l1 cost, max values is already checked in pre_validate but l1 cost wasn't.
pre_execution::validate_against_state_and_deduct_caller::<_, ERROR>(ctx)?;
}

// process rollup fee
if !is_l1_msg && !is_system_tx {
let l1_block_info = ctx.chain().clone();
let Some(rlp_bytes) = ctx.tx().rlp_bytes() else {
return Err(ERROR::from_string(
Expand All @@ -112,7 +117,10 @@ where
}
caller_account.data.info.balance =
caller_account.data.info.balance.saturating_sub(tx_l1_cost);
} else {
}

// execute l1 msg checks
if is_l1_msg {
// Load caller's account.
let (tx, journal) = ctx.tx_journal();
let mut caller_account = journal.load_account(caller)?;
Expand Down
23 changes: 23 additions & 0 deletions src/tests/fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::{
builder::ScrollBuilder,
handler::ScrollHandler,
test_utils::{context_with_funds, CALLER},
transaction::SYSTEM_ADDRESS,
ScrollSpecId,
};
use std::boxed::Box;
Expand Down Expand Up @@ -45,3 +46,25 @@ fn test_should_deduct_correct_fees_curie() -> Result<(), Box<dyn core::error::Er

Ok(())
}

#[test]
fn test_no_rollup_fee_for_system_tx() -> Result<(), Box<dyn core::error::Error>> {
let ctx = context_with_funds(U256::from(70_000))
.modify_cfg_chained(|cfg| cfg.spec = ScrollSpecId::CURIE)
.modify_tx_chained(|tx| {
tx.base.caller = SYSTEM_ADDRESS;
tx.base.gas_price = 0
});

let mut evm = ctx.clone().build_scroll();
let handler = ScrollHandler::<_, EVMError<_>, EthFrame<_, _, _>>::new();

handler.pre_execution(&mut evm).unwrap();

let caller_account = evm.ctx().journal().load_account(CALLER)?;

// gas price is 0, no data fee => balance is unchanged.
assert_eq!(caller_account.data.info.balance, U256::from(70_000));

Ok(())
}
12 changes: 11 additions & 1 deletion src/transaction.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
use revm::context::{Transaction, TxEnv};
use revm_primitives::{Address, Bytes, TxKind, B256, U256};
use revm_primitives::{address, Address, Bytes, TxKind, B256, U256};

/// The type for a l1 message transaction.
pub const L1_MESSAGE_TYPE: u8 = 0x7E;

/// The caller address of EIP-2935 system transactions.
pub const SYSTEM_ADDRESS: Address = address!("0xfffffffffffffffffffffffffffffffffffffffe");

#[auto_impl::auto_impl(&, Arc, Box)]
pub trait ScrollTxTr: Transaction {
/// Whether the transaction is an L1 message.
fn is_l1_msg(&self) -> bool;

/// Whether the transaction is a system transaction (e.g. EIP-2935).
fn is_system_tx(&self) -> bool;

/// The RLP encoded transaction bytes which are used to calculate the cost associated with
/// posting the transaction on L1.
fn rlp_bytes(&self) -> Option<&Bytes>;
Expand Down Expand Up @@ -111,6 +117,10 @@ impl<T: Transaction> ScrollTxTr for ScrollTransaction<T> {
self.tx_type() == L1_MESSAGE_TYPE
}

fn is_system_tx(&self) -> bool {
self.caller() == SYSTEM_ADDRESS
}

fn rlp_bytes(&self) -> Option<&Bytes> {
self.rlp_bytes.as_ref()
}
Expand Down