arb_evm/
hooks.rs

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