Skip to main content

ethrex_l2_common/
privileged_transactions.rs

1use ethereum_types::{Address, H256, U256};
2use ethrex_common::types::{PrivilegedL2Transaction, Transaction};
3use ethrex_common::utils::keccak;
4use serde::{Deserialize, Serialize};
5
6/// Max privileged tx to allow per batch
7pub const PRIVILEGED_TX_BUDGET: u64 = 300;
8
9#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10pub struct PrivilegedTransactionLog {
11    pub address: Address,
12    pub amount: U256,
13    pub nonce: u64,
14}
15
16impl PrivilegedTransactionLog {
17    pub fn encode(&self) -> Vec<u8> {
18        let mut encoded = Vec::new();
19        encoded.extend(self.address.0);
20        encoded.extend_from_slice(&self.amount.to_big_endian());
21        encoded
22    }
23}
24
25#[derive(Debug, thiserror::Error)]
26pub enum PrivilegedTransactionError {
27    #[error("Failed to decode transaction hash")]
28    FailedToDecodeHash,
29    #[error("Length does not fit in u16")]
30    LengthTooLarge(#[from] std::num::TryFromIntError),
31}
32
33pub fn get_block_l1_in_messages(
34    txs: &[Transaction],
35    chain_id: u64,
36) -> Vec<PrivilegedL2Transaction> {
37    txs.iter()
38        .filter_map(|tx| {
39            if let Transaction::PrivilegedL2Transaction(tx) = tx {
40                // The chain id of the L1-in message should match the chain id of the current chain
41                if tx.chain_id == chain_id {
42                    return Some(tx.clone());
43                }
44                None
45            } else {
46                None
47            }
48        })
49        .collect()
50}
51
52pub fn get_block_l2_in_messages(
53    txs: &[Transaction],
54    chain_id: u64,
55) -> Vec<PrivilegedL2Transaction> {
56    txs.iter()
57        .filter_map(|tx| {
58            if let Transaction::PrivilegedL2Transaction(tx) = tx {
59                // The chain id of the L2-in message is the chain id of the source chain
60                if tx.chain_id != chain_id {
61                    return Some(tx.clone());
62                }
63                None
64            } else {
65                None
66            }
67        })
68        .collect()
69}
70
71pub fn compute_privileged_transactions_hash(
72    privileged_transaction_hashes: Vec<H256>,
73) -> Result<H256, PrivilegedTransactionError> {
74    if privileged_transaction_hashes.is_empty() {
75        return Ok(H256::zero());
76    }
77
78    let privileged_transaction_hashes_len: u16 = privileged_transaction_hashes.len().try_into()?;
79
80    Ok(H256::from_slice(
81        [
82            &privileged_transaction_hashes_len.to_be_bytes(),
83            keccak(
84                privileged_transaction_hashes
85                    .iter()
86                    .map(H256::as_bytes)
87                    .collect::<Vec<&[u8]>>()
88                    .concat(),
89            )
90            .as_bytes()
91            .get(2..32)
92            .ok_or(PrivilegedTransactionError::FailedToDecodeHash)?,
93        ]
94        .concat()
95        .as_slice(),
96    ))
97}