1use alloy_consensus::{BlockHeader, Header};
7use alloy_primitives::{B256, U256};
8use alloy_rpc_types_eth::Header as RpcHeader;
9use alloy_serde::WithOtherFields;
10use reth_primitives_traits::SealedHeader;
11use reth_rpc_convert::transaction::HeaderConverter;
12use std::convert::Infallible;
13
14pub fn l1_block_number_from_mix_hash(mix_hash: &B256) -> u64 {
16 u64::from_be_bytes(mix_hash.0[8..16].try_into().unwrap_or_default())
17}
18
19#[derive(Debug, Clone)]
21pub struct ArbHeaderConverter;
22
23impl HeaderConverter<Header, WithOtherFields<RpcHeader<Header>>> for ArbHeaderConverter {
24 type Err = Infallible;
25
26 fn convert_header(
27 &self,
28 header: SealedHeader<Header>,
29 block_size: usize,
30 ) -> Result<WithOtherFields<RpcHeader<Header>>, Self::Err> {
31 let mix = header.mix_hash().unwrap_or_default();
32 let extra = header.extra_data();
33
34 let send_count = u64::from_be_bytes(mix.0[0..8].try_into().unwrap_or_default());
36 let l1_block_number = u64::from_be_bytes(mix.0[8..16].try_into().unwrap_or_default());
37
38 let send_root = if extra.len() >= 32 {
40 B256::from_slice(&extra[..32])
41 } else {
42 B256::ZERO
43 };
44
45 let base_header =
46 RpcHeader::from_consensus(header.into(), None, Some(U256::from(block_size)));
47
48 let mut other = std::collections::BTreeMap::new();
49 other.insert(
50 "sendRoot".to_string(),
51 serde_json::to_value(send_root).unwrap_or_default(),
52 );
53 other.insert(
54 "sendCount".to_string(),
55 serde_json::to_value(format!("{send_count:#x}")).unwrap_or_default(),
56 );
57 other.insert(
58 "l1BlockNumber".to_string(),
59 serde_json::to_value(format!("{l1_block_number:#x}")).unwrap_or_default(),
60 );
61
62 Ok(WithOtherFields {
63 inner: base_header,
64 other: alloy_serde::OtherFields::new(other),
65 })
66 }
67}