1use alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec};
2use alloy_primitives::{B512, U256};
3
4#[derive(Clone, Debug, Default, PartialEq, Eq)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
8pub struct SyncInfo {
9 pub starting_block: U256,
11 pub current_block: U256,
13 pub highest_block: U256,
15 pub warp_chunks_amount: Option<U256>,
17 pub warp_chunks_processed: Option<U256>,
19 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
22 pub stages: Option<Vec<Stage>>,
23}
24
25#[derive(Clone, Debug, Default, PartialEq, Eq)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
29pub struct Stage {
30 #[cfg_attr(feature = "serde", serde(alias = "stage_name"))]
32 pub name: String,
33 #[cfg_attr(feature = "serde", serde(alias = "block_number", with = "alloy_serde::quantity"))]
35 pub block: u64,
36}
37
38#[derive(Clone, Debug, Default, PartialEq, Eq)]
40#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
41pub struct Peers {
42 pub active: usize,
44 pub connected: usize,
46 pub max: u32,
48 pub peers: Vec<PeerInfo>,
50}
51
52#[derive(Clone, Debug, Default, PartialEq, Eq)]
54#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
55pub struct PeerInfo {
56 pub id: Option<String>,
58 pub name: String,
60 pub caps: Vec<String>,
62 pub network: PeerNetworkInfo,
64 pub protocols: PeerProtocolsInfo,
66}
67
68#[derive(Clone, Debug, Default, PartialEq, Eq)]
70#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
71#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
72pub struct PeerNetworkInfo {
73 pub remote_address: String,
75 pub local_address: String,
77}
78
79#[derive(Clone, Debug, Default, PartialEq, Eq)]
81#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
82pub struct PeerProtocolsInfo {
83 pub eth: Option<PeerEthProtocolInfo>,
85 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
87 pub pip: Option<PipProtocolInfo>,
88}
89
90#[derive(Clone, Debug, Default, PartialEq, Eq)]
92#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
93pub struct PeerEthProtocolInfo {
94 pub version: u32,
96 pub difficulty: Option<U256>,
98 pub head: String,
100}
101
102#[derive(Clone, Debug, Default, PartialEq, Eq)]
104#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
105pub struct PipProtocolInfo {
106 pub version: u32,
108 pub difficulty: U256,
110 pub head: String,
112}
113
114#[derive(Clone, Debug, PartialEq, Eq)]
116pub enum SyncStatus {
117 Info(Box<SyncInfo>),
119 None,
121}
122
123#[cfg(feature = "serde")]
124impl<'de> serde::Deserialize<'de> for SyncStatus {
125 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
126 where
127 D: serde::Deserializer<'de>,
128 {
129 #[derive(serde::Deserialize)]
130 #[serde(untagged)]
131 enum Syncing {
132 None(bool),
134 IsSyncing(Box<SyncInfo>),
135 }
136
137 match Syncing::deserialize(deserializer)? {
138 Syncing::None(false) => Ok(Self::None),
139 Syncing::None(true) => Err(serde::de::Error::custom(
140 "eth_syncing returned `true` that is undefined value.",
141 )),
142 Syncing::IsSyncing(sync) => Ok(Self::Info(sync)),
143 }
144 }
145}
146
147#[cfg(feature = "serde")]
148impl serde::Serialize for SyncStatus {
149 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
150 where
151 S: serde::Serializer,
152 {
153 match self {
154 Self::Info(info) => info.serialize(serializer),
155 Self::None => serializer.serialize_bool(false),
156 }
157 }
158}
159
160#[derive(Clone, Debug, Default)]
162#[cfg_attr(feature = "serde", derive(serde::Serialize))]
163#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
164#[doc(alias = "TxStats")]
165pub struct TransactionStats {
166 pub first_seen: u64,
168 pub propagated_to: BTreeMap<B512, usize>,
170}
171
172#[derive(Clone, Copy, Debug, Default)]
174#[cfg_attr(feature = "serde", derive(serde::Serialize))]
175#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
176pub struct ChainStatus {
177 pub block_gap: Option<(U256, U256)>,
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 #[test]
186 #[cfg(feature = "serde")]
187 fn test_sync_info_serialization() {
188 let sync_info = SyncInfo {
189 starting_block: U256::from(0x3cbed5),
190 current_block: U256::from(0x3cf522),
191 highest_block: U256::from(0x3e0e41),
192 warp_chunks_amount: Some(U256::from(10)),
193 warp_chunks_processed: Some(U256::from(5)),
194 stages: Some(vec![
195 Stage { name: "Stage 1".to_string(), block: 1000 },
196 Stage { name: "Stage 2".to_string(), block: 2000 },
197 ]),
198 };
199
200 let serialized = serde_json::to_string(&sync_info).expect("Serialization failed");
201 let deserialized: SyncInfo =
202 serde_json::from_str(&serialized).expect("Deserialization failed");
203
204 assert_eq!(sync_info, deserialized);
205 }
206
207 #[test]
208 #[cfg(feature = "serde")]
209 fn test_peer_info_serialization() {
210 let peer_info = PeerInfo {
211 id: Some("peer_id_123".to_string()),
212 name: "GethClient".to_string(),
213 caps: vec!["eth/66".to_string(), "les/2".to_string()],
214 network: PeerNetworkInfo {
215 remote_address: "192.168.1.1:30303".to_string(),
216 local_address: "127.0.0.1:30303".to_string(),
217 },
218 protocols: PeerProtocolsInfo {
219 eth: Some(PeerEthProtocolInfo {
220 version: 66,
221 difficulty: Some(U256::from(1000000)),
222 head: "0xabcdef".to_string(),
223 }),
224 pip: None,
225 },
226 };
227
228 let serialized = serde_json::to_string(&peer_info).expect("Serialization failed");
229 let deserialized: PeerInfo =
230 serde_json::from_str(&serialized).expect("Deserialization failed");
231
232 assert_eq!(peer_info, deserialized);
233 }
234
235 #[test]
236 #[cfg(feature = "serde")]
237 fn test_sync_status_serialization() {
238 let sync_status = SyncStatus::Info(Box::new(SyncInfo {
239 starting_block: U256::from(0x3cbed5),
240 current_block: U256::from(0x3cf522),
241 highest_block: U256::from(0x3e0e41),
242 warp_chunks_amount: None,
243 warp_chunks_processed: None,
244 stages: None,
245 }));
246
247 let serialized = serde_json::to_string(&sync_status).expect("Serialization failed");
248 let deserialized: SyncStatus =
249 serde_json::from_str(&serialized).expect("Deserialization failed");
250
251 assert_eq!(sync_status, deserialized);
252
253 let none_status = SyncStatus::None;
254 let serialized_none = serde_json::to_string(&none_status).expect("Serialization failed");
255 let deserialized_none: SyncStatus =
256 serde_json::from_str(&serialized_none).expect("Deserialization failed");
257
258 assert_eq!(none_status, deserialized_none);
259 }
260}