arb_rpc/block_producer.rs
1//! Block producer trait for the `nitroexecution` RPC handler.
2//!
3//! Defines the interface for producing blocks from L1 incoming messages.
4//! The concrete implementation lives in `arb-node` where it has access
5//! to the full node infrastructure (database, EVM config, state).
6
7use alloy_primitives::B256;
8
9/// Result of producing a block.
10#[derive(Debug, Clone)]
11pub struct ProducedBlock {
12 /// Hash of the produced block.
13 pub block_hash: B256,
14 /// Send root from the block's extra_data.
15 pub send_root: B256,
16}
17
18/// Error type for block production.
19#[derive(Debug, thiserror::Error)]
20pub enum BlockProducerError {
21 #[error("state access: {0}")]
22 StateAccess(String),
23 #[error("execution: {0}")]
24 Execution(String),
25 #[error("storage: {0}")]
26 Storage(String),
27 #[error("parse: {0}")]
28 Parse(String),
29 #[error("unexpected: {0}")]
30 Unexpected(String),
31}
32
33/// Input for block production from an L1 incoming message.
34#[derive(Debug, Clone)]
35pub struct BlockProductionInput {
36 /// Message kind (L1MessageType_*).
37 pub kind: u8,
38 /// Message sender (poster address).
39 pub sender: alloy_primitives::Address,
40 /// L1 block number.
41 pub l1_block_number: u64,
42 /// L1 timestamp.
43 pub l1_timestamp: u64,
44 /// L1 request ID (for delayed messages).
45 pub request_id: Option<B256>,
46 /// L1 base fee.
47 pub l1_base_fee: Option<alloy_primitives::U256>,
48 /// L2 message payload (base64-decoded).
49 pub l2_msg: Vec<u8>,
50 /// Delayed messages read count.
51 pub delayed_messages_read: u64,
52 /// Legacy batch gas cost.
53 pub batch_gas_cost: Option<u64>,
54 /// Batch data stats (for newer batch posting reports).
55 pub batch_data_stats: Option<(u64, u64)>,
56}
57
58/// Trait for producing blocks from L1 messages.
59///
60/// Implemented by the node infrastructure where full database and EVM
61/// access is available.
62#[async_trait::async_trait]
63pub trait BlockProducer: Send + Sync + 'static {
64 /// Cache the Init message params for later use during block 1 execution.
65 ///
66 /// The Init message (Kind=11) does NOT produce a block. Its params are
67 /// applied during the first real block's pre-execution so that the
68 /// state root for block 1 includes both Init and execution changes.
69 fn cache_init_message(&self, l2_msg: &[u8]) -> Result<(), BlockProducerError>;
70
71 /// Produce a block from the given L1 incoming message.
72 ///
73 /// The implementation should:
74 /// 1. Parse the L1 message into transactions
75 /// 2. Open the state at the current head
76 /// 3. Execute transactions using the ArbOS pipeline
77 /// 4. Compute the state root
78 /// 5. Persist the block and state changes
79 /// 6. Return the block hash and send root
80 async fn produce_block(
81 &self,
82 msg_idx: u64,
83 input: BlockProductionInput,
84 ) -> Result<ProducedBlock, BlockProducerError>;
85}