arbos/filtered_transactions/
mod.rs

1use alloy_primitives::{B256, U256};
2use arb_storage::{Storage, StorageBackend, SystemStateBackend};
3use revm::Database;
4
5mod error;
6pub use error::FilteredTxError;
7
8const PRESENT_HASH: B256 = {
9    let mut bytes = [0u8; 32];
10    bytes[31] = 1;
11    B256::new(bytes)
12};
13
14/// Tracks transaction hashes that have been filtered (censored/blocked).
15pub struct FilteredTransactionsState<'a, D> {
16    store: Storage<'a, D>,
17}
18
19impl<'a, D> FilteredTransactionsState<'a, D> {
20    pub fn open(sto: Storage<'a, D>) -> Self {
21        Self { store: sto }
22    }
23
24    pub fn set<B: StorageBackend>(
25        &self,
26        backend: &mut B,
27        tx_hash: B256,
28        present: bool,
29    ) -> Result<(), FilteredTxError> {
30        let value = if present {
31            U256::from_be_bytes(PRESENT_HASH.0)
32        } else {
33            U256::ZERO
34        };
35        backend
36            .sstore(
37                self.store.account(),
38                self.store.slot_for_key(tx_hash),
39                value,
40            )
41            .map_err(Into::into)?;
42        Ok(())
43    }
44
45    pub fn is_filtered<B: SystemStateBackend>(
46        &self,
47        backend: &mut B,
48        tx_hash: B256,
49    ) -> Result<bool, FilteredTxError> {
50        let value = backend
51            .sload_system(self.store.account(), self.store.slot_for_key(tx_hash))
52            .map_err(Into::into)?;
53        Ok(value == U256::from_be_bytes(PRESENT_HASH.0))
54    }
55}
56
57impl<D: Database> FilteredTransactionsState<'_, D> {
58    /// Check if a tx is filtered without charging gas.
59    pub fn is_filtered_free(&self, tx_hash: B256) -> bool {
60        self.store
61            .get(tx_hash)
62            .map(|v| v == PRESENT_HASH)
63            .unwrap_or(false)
64    }
65}