1use alloy_primitives::{Address, B256, U256};
9use jsonrpsee::{core::RpcResult, proc_macros::rpc};
10use serde::{Deserialize, Serialize};
11
12mod opt_u256_dec_or_hex {
16 use alloy_primitives::U256;
17 use serde::{self, Deserialize, Deserializer, Serializer};
18
19 pub fn serialize<S>(value: &Option<U256>, serializer: S) -> Result<S::Ok, S::Error>
20 where
21 S: Serializer,
22 {
23 match value {
24 Some(v) => serde::Serialize::serialize(v, serializer),
25 None => serializer.serialize_none(),
26 }
27 }
28
29 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<U256>, D::Error>
30 where
31 D: Deserializer<'de>,
32 {
33 let v = serde_json::Value::deserialize(deserializer)?;
34 match v {
35 serde_json::Value::Null => Ok(None),
36 serde_json::Value::Number(n) => {
37 if let Some(u) = n.as_u64() {
38 Ok(Some(U256::from(u)))
39 } else {
40 let val = U256::from_str_radix(&n.to_string(), 10)
41 .map_err(serde::de::Error::custom)?;
42 Ok(Some(val))
43 }
44 }
45 serde_json::Value::String(s) if s.is_empty() => Ok(None),
46 serde_json::Value::String(s) => {
47 let val = if let Some(hex) = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")) {
48 U256::from_str_radix(hex, 16).map_err(serde::de::Error::custom)?
49 } else {
50 U256::from_str_radix(&s, 10).map_err(serde::de::Error::custom)?
51 };
52 Ok(Some(val))
53 }
54 _ => Err(serde::de::Error::custom(
55 "expected number, string, or null for U256",
56 )),
57 }
58 }
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct RpcL1IncomingMessageHeader {
69 pub kind: u8,
70 pub sender: Address,
71 #[serde(rename = "blockNumber")]
72 pub block_number: u64,
73 pub timestamp: u64,
74 #[serde(default, skip_serializing_if = "Option::is_none", rename = "requestId")]
75 pub request_id: Option<B256>,
76 #[serde(
77 default,
78 skip_serializing_if = "Option::is_none",
79 rename = "baseFeeL1",
80 with = "opt_u256_dec_or_hex"
81 )]
82 pub base_fee_l1: Option<U256>,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct RpcBatchDataStats {
89 pub length: u64,
90 pub nonzeros: u64,
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct RpcL1IncomingMessage {
97 pub header: RpcL1IncomingMessageHeader,
98 #[serde(default, skip_serializing_if = "Option::is_none", rename = "l2Msg")]
100 pub l2_msg: Option<String>,
101 #[serde(
103 default,
104 skip_serializing_if = "Option::is_none",
105 rename = "batchGasCost"
106 )]
107 pub batch_gas_cost: Option<u64>,
108 #[serde(
110 default,
111 skip_serializing_if = "Option::is_none",
112 rename = "batchDataTokens"
113 )]
114 pub batch_data_tokens: Option<RpcBatchDataStats>,
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct RpcMessageWithMetadata {
121 pub message: RpcL1IncomingMessage,
122 #[serde(rename = "delayedMessagesRead")]
123 pub delayed_messages_read: u64,
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
129#[serde(rename_all = "PascalCase")]
130pub struct RpcMessageWithMetadataAndBlockInfo {
131 #[serde(rename = "MessageWithMeta")]
132 pub message: RpcMessageWithMetadata,
133 #[serde(default, skip_serializing_if = "Option::is_none")]
134 pub block_hash: Option<B256>,
135 #[serde(default, skip_serializing_if = "Option::is_none")]
136 pub block_metadata: Option<Vec<u8>>,
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
142#[serde(rename_all = "PascalCase")]
143pub struct RpcMessageResult {
144 pub block_hash: B256,
145 pub send_root: B256,
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
151#[serde(rename_all = "PascalCase")]
152pub struct RpcFinalityData {
153 #[serde(default)]
154 pub msg_idx: u64,
155 #[serde(default)]
156 pub block_hash: B256,
157}
158
159#[derive(Debug, Clone, Serialize, Deserialize)]
162#[serde(rename_all = "PascalCase")]
163pub struct RpcConsensusSyncData {
164 pub synced: bool,
165 pub max_message_count: u64,
166 #[serde(default)]
167 pub sync_progress_map: Option<serde_json::Value>,
168 #[serde(default)]
169 pub updated_at: Option<String>,
170}
171
172#[derive(Debug, Clone, Default, Serialize, Deserialize)]
175#[serde(rename_all = "PascalCase")]
176pub struct RpcMaintenanceStatus {
177 pub is_running: bool,
178}
179
180#[rpc(server, namespace = "nitroexecution")]
189pub trait NitroExecutionApi {
190 #[method(name = "digestMessage")]
192 async fn digest_message(
193 &self,
194 msg_idx: u64,
195 message: RpcMessageWithMetadata,
196 message_for_prefetch: Option<RpcMessageWithMetadata>,
197 ) -> RpcResult<RpcMessageResult>;
198
199 #[method(name = "reorg")]
201 async fn reorg(
202 &self,
203 msg_idx_of_first_msg_to_add: u64,
204 new_messages: Vec<RpcMessageWithMetadataAndBlockInfo>,
205 old_messages: Vec<RpcMessageWithMetadata>,
206 ) -> RpcResult<Vec<RpcMessageResult>>;
207
208 #[method(name = "headMessageIndex")]
210 async fn head_message_index(&self) -> RpcResult<u64>;
211
212 #[method(name = "resultAtMessageIndex")]
214 async fn result_at_message_index(&self, msg_idx: u64) -> RpcResult<RpcMessageResult>;
215
216 #[method(name = "setFinalityData")]
218 fn set_finality_data(
219 &self,
220 safe: Option<RpcFinalityData>,
221 finalized: Option<RpcFinalityData>,
222 validated: Option<RpcFinalityData>,
223 ) -> RpcResult<()>;
224
225 #[method(name = "setConsensusSyncData")]
227 fn set_consensus_sync_data(&self, sync_data: RpcConsensusSyncData) -> RpcResult<()>;
228
229 #[method(name = "markFeedStart")]
231 fn mark_feed_start(&self, to: u64) -> RpcResult<()>;
232
233 #[method(name = "triggerMaintenance")]
235 async fn trigger_maintenance(&self) -> RpcResult<()>;
236
237 #[method(name = "shouldTriggerMaintenance")]
239 async fn should_trigger_maintenance(&self) -> RpcResult<bool>;
240
241 #[method(name = "maintenanceStatus")]
243 async fn maintenance_status(&self) -> RpcResult<RpcMaintenanceStatus>;
244
245 #[method(name = "arbOSVersionForMessageIndex")]
247 async fn arbos_version_for_message_index(&self, msg_idx: u64) -> RpcResult<u64>;
248}