1use std::sync::Arc;
7
8use alloy_consensus::BlockHeader;
9use alloy_primitives::B256;
10use alloy_rpc_types_eth::BlockNumberOrTag;
11use jsonrpsee::{core::RpcResult, proc_macros::rpc};
12use reth_provider::{BlockNumReader, BlockReaderIdExt, HeaderProvider};
13
14use crate::{ArbBlockInfo, ArbMaintenanceStatus};
15
16#[rpc(server, namespace = "arb")]
18pub trait ArbApi {
19 #[method(name = "maintenanceStatus")]
21 fn maintenance_status(&self) -> RpcResult<ArbMaintenanceStatus>;
22
23 #[method(name = "checkPublisherHealth")]
25 fn check_publisher_health(&self) -> RpcResult<()>;
26
27 #[method(name = "getBlockInfo")]
29 async fn get_block_info(&self, block_num: u64) -> RpcResult<ArbBlockInfo>;
30}
31
32pub struct ArbApiHandler<Provider> {
34 provider: Provider,
35 maintenance_status: Arc<parking_lot::RwLock<ArbMaintenanceStatus>>,
37}
38
39impl<Provider> ArbApiHandler<Provider> {
40 pub fn new(provider: Provider) -> Self {
42 Self {
43 provider,
44 maintenance_status: Arc::new(parking_lot::RwLock::new(ArbMaintenanceStatus::default())),
45 }
46 }
47
48 pub fn maintenance_status_handle(&self) -> Arc<parking_lot::RwLock<ArbMaintenanceStatus>> {
50 self.maintenance_status.clone()
51 }
52}
53
54#[async_trait::async_trait]
55impl<Provider> ArbApiServer for ArbApiHandler<Provider>
56where
57 Provider: BlockNumReader + BlockReaderIdExt + HeaderProvider + 'static,
58{
59 fn maintenance_status(&self) -> RpcResult<ArbMaintenanceStatus> {
60 Ok(self.maintenance_status.read().clone())
61 }
62
63 fn check_publisher_health(&self) -> RpcResult<()> {
64 Ok(())
66 }
67
68 async fn get_block_info(&self, block_num: u64) -> RpcResult<ArbBlockInfo> {
69 let header = self
70 .provider
71 .sealed_header_by_number_or_tag(BlockNumberOrTag::Number(block_num))
72 .map_err(|e| {
73 jsonrpsee::types::ErrorObject::owned(
74 jsonrpsee::types::error::INTERNAL_ERROR_CODE,
75 e.to_string(),
76 None::<()>,
77 )
78 })?
79 .ok_or_else(|| {
80 jsonrpsee::types::ErrorObject::owned(
81 jsonrpsee::types::error::INVALID_PARAMS_CODE,
82 format!("block {block_num} not found"),
83 None::<()>,
84 )
85 })?;
86
87 let mix = header.mix_hash().unwrap_or_default();
88 let extra = header.extra_data();
89
90 let send_count = u64::from_be_bytes(mix.0[0..8].try_into().unwrap_or_default());
91 let l1_block_number = u64::from_be_bytes(mix.0[8..16].try_into().unwrap_or_default());
92 let arbos_format_version = u64::from_be_bytes(mix.0[16..24].try_into().unwrap_or_default());
93
94 let send_root = if extra.len() >= 32 {
95 B256::from_slice(&extra[..32])
96 } else {
97 B256::ZERO
98 };
99
100 Ok(ArbBlockInfo {
101 l1_block_number,
102 arbos_format_version,
103 send_count,
104 send_root,
105 })
106 }
107}