arb_evm/
hooks.rs

1use alloy_primitives::{Address, U256};
2
3use arb_primitives::{multigas::MultiGas, tx_types::ArbTxType};
4
5/// Context passed to ArbOS hooks at the start of transaction execution.
6#[derive(Debug, Clone)]
7pub struct StartTxContext {
8    pub sender: Address,
9    pub to: Option<Address>,
10    pub nonce: u64,
11    pub gas_limit: u64,
12    pub gas_price: U256,
13    pub value: U256,
14    pub data: Vec<u8>,
15    pub tx_type: ArbTxType,
16    pub is_gas_estimation: bool,
17}
18
19/// Context passed to the gas charging hook.
20#[derive(Debug, Clone)]
21pub struct GasChargingContext {
22    pub sender: Address,
23    pub poster_address: Address,
24    pub gas_limit: u64,
25    pub intrinsic_gas: u64,
26    pub gas_price: U256,
27    pub base_fee: U256,
28    pub tx_type: ArbTxType,
29    /// Pre-computed poster cost in ETH (price_per_unit * brotli_units).
30    /// Computed by the block executor using L1PricingState with brotli compression.
31    pub poster_cost: U256,
32    /// Pre-computed calldata units for L1 pricing state tracking.
33    pub calldata_units: u64,
34}
35
36/// Result from gas charging.
37#[derive(Debug, Clone, Default)]
38pub struct GasChargingResult {
39    pub poster_cost: U256,
40    pub poster_gas: u64,
41    pub compute_hold_gas: u64,
42    /// Calldata units to add to L1 pricing state's units_since_update.
43    pub calldata_units: u64,
44    /// Multi-dimensional gas consumed during gas charging (L1 calldata component).
45    pub multi_gas: MultiGas,
46}
47
48/// Context passed to the end-of-transaction hook.
49#[derive(Debug, Clone)]
50pub struct EndTxContext {
51    pub sender: Address,
52    pub gas_left: u64,
53    pub gas_used: u64,
54    pub gas_price: U256,
55    pub base_fee: U256,
56    pub tx_type: ArbTxType,
57    pub success: bool,
58    pub refund_to: Address,
59}
60
61/// Hooks for ArbOS-specific transaction processing.
62///
63/// These hooks integrate ArbOS state management into reth's block execution.
64/// These correspond to the canonical `TxProcessor`'s `StartTxHook`,
65/// `GasChargingHook`, and `EndTxHook`.
66pub trait ArbOsHooks {
67    type Error: core::fmt::Debug;
68
69    /// Called before each transaction. Sets up gas accounting,
70    /// processes deposits, and initializes retryable state.
71    fn start_tx(&mut self, ctx: &StartTxContext) -> Result<(), Self::Error>;
72
73    /// Called after intrinsic gas calculation. Charges poster costs
74    /// and manages L1 pricing.
75    fn gas_charging(&mut self, ctx: &GasChargingContext) -> Result<GasChargingResult, Self::Error>;
76
77    /// Called after transaction execution. Handles gas refunds,
78    /// poster fee distribution, and state cleanup.
79    fn end_tx(&mut self, ctx: &EndTxContext) -> Result<(), Self::Error>;
80
81    /// Returns the amount of gas that cannot be refunded.
82    fn nonrefundable_gas(&self) -> u64;
83
84    /// Returns the amount of gas held for compute.
85    fn held_gas(&self) -> u64;
86
87    /// Returns scheduled internal transactions generated during execution.
88    fn scheduled_txs(&mut self) -> Vec<Vec<u8>>;
89
90    /// Whether the priority fee tip should be dropped (not sent to coinbase).
91    fn drop_tip(&self) -> bool;
92
93    /// The effective gas price for the GASPRICE opcode.
94    fn gas_price_op(&self, gas_price: U256, base_fee: U256) -> U256;
95
96    /// Whether the message is non-mutating (eth_call).
97    fn msg_is_non_mutating(&self) -> bool;
98
99    /// Whether EIP-7623 calldata pricing increase is enabled.
100    fn is_calldata_pricing_increase_enabled(&self) -> bool;
101}
102
103/// No-op implementation for testing.
104pub struct NoopArbOsHooks;
105
106impl ArbOsHooks for NoopArbOsHooks {
107    type Error = ();
108
109    fn start_tx(&mut self, _ctx: &StartTxContext) -> Result<(), ()> {
110        Ok(())
111    }
112
113    fn gas_charging(&mut self, _ctx: &GasChargingContext) -> Result<GasChargingResult, ()> {
114        Ok(GasChargingResult::default())
115    }
116
117    fn end_tx(&mut self, _ctx: &EndTxContext) -> Result<(), ()> {
118        Ok(())
119    }
120
121    fn nonrefundable_gas(&self) -> u64 {
122        0
123    }
124
125    fn held_gas(&self) -> u64 {
126        0
127    }
128
129    fn scheduled_txs(&mut self) -> Vec<Vec<u8>> {
130        vec![]
131    }
132
133    fn drop_tip(&self) -> bool {
134        false
135    }
136
137    fn gas_price_op(&self, gas_price: U256, _base_fee: U256) -> U256 {
138        gas_price
139    }
140
141    fn msg_is_non_mutating(&self) -> bool {
142        false
143    }
144
145    fn is_calldata_pricing_increase_enabled(&self) -> bool {
146        true
147    }
148}