1use crate::block::Checkpoint;
6use alloy_primitives::B256;
7use serde::{Deserialize, Serialize};
8use serde_with::{serde_as, DisplayFromStr};
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub struct CommitteesResponse {
13 #[serde(default)]
15 pub execution_optimistic: bool,
16 #[serde(default)]
18 pub finalized: bool,
19 pub data: Vec<Committee>,
21}
22
23#[serde_as]
25#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
26pub struct Committee {
27 #[serde_as(as = "DisplayFromStr")]
29 pub index: u64,
30 #[serde_as(as = "DisplayFromStr")]
32 pub slot: u64,
33 #[serde_as(as = "Vec<DisplayFromStr>")]
35 pub validators: Vec<u64>,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40pub struct SyncCommitteesResponse {
41 #[serde(default)]
43 pub execution_optimistic: bool,
44 #[serde(default)]
46 pub finalized: bool,
47 pub data: SyncCommittee,
49}
50
51#[serde_as]
53#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
54pub struct SyncCommittee {
55 #[serde_as(as = "Vec<DisplayFromStr>")]
57 pub validators: Vec<u64>,
58 #[serde_as(as = "Vec<Vec<DisplayFromStr>>")]
60 pub validator_aggregates: Vec<Vec<u64>>,
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
65pub struct FinalityCheckpointsResponse {
66 #[serde(default)]
68 pub execution_optimistic: bool,
69 #[serde(default)]
71 pub finalized: bool,
72 pub data: FinalityCheckpoints,
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
78pub struct FinalityCheckpoints {
79 pub previous_justified: Checkpoint,
81 pub current_justified: Checkpoint,
83 pub finalized: Checkpoint,
85}
86
87#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
89pub struct ValidatorBalancesResponse {
90 #[serde(default)]
92 pub execution_optimistic: bool,
93 #[serde(default)]
95 pub finalized: bool,
96 pub data: Vec<ValidatorBalance>,
98}
99
100#[serde_as]
102#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
103pub struct ValidatorBalance {
104 #[serde_as(as = "DisplayFromStr")]
106 pub index: u64,
107 #[serde_as(as = "DisplayFromStr")]
109 pub balance: u64,
110}
111
112#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
114pub struct RandaoResponse {
115 #[serde(default)]
117 pub execution_optimistic: bool,
118 #[serde(default)]
120 pub finalized: bool,
121 pub data: RandaoData,
123}
124
125#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
127pub struct RandaoData {
128 pub randao: B256,
130}
131
132#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
134pub struct StateRootResponse {
135 #[serde(default)]
137 pub execution_optimistic: bool,
138 #[serde(default)]
140 pub finalized: bool,
141 pub data: StateRootData,
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
147pub struct StateRootData {
148 pub root: B256,
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn serde_committees_response() {
158 let s = r#"{
159 "execution_optimistic": false,
160 "finalized": true,
161 "data": [
162 {
163 "index": "1",
164 "slot": "2",
165 "validators": ["0", "1", "2"]
166 }
167 ]
168 }"#;
169 let resp: CommitteesResponse = serde_json::from_str(s).unwrap();
170 assert_eq!(resp.data.len(), 1);
171 assert_eq!(resp.data[0].index, 1);
172 assert_eq!(resp.data[0].slot, 2);
173 assert_eq!(resp.data[0].validators, vec![0, 1, 2]);
174 assert!(resp.finalized);
175 assert!(!resp.execution_optimistic);
176
177 let roundtrip: CommitteesResponse =
178 serde_json::from_str(&serde_json::to_string(&resp).unwrap()).unwrap();
179 assert_eq!(resp, roundtrip);
180 }
181
182 #[test]
183 fn serde_sync_committees_response() {
184 let s = r#"{
185 "execution_optimistic": false,
186 "finalized": true,
187 "data": {
188 "validators": ["0", "1", "2", "3"],
189 "validator_aggregates": [
190 ["0", "1"],
191 ["2", "3"]
192 ]
193 }
194 }"#;
195 let resp: SyncCommitteesResponse = serde_json::from_str(s).unwrap();
196 assert_eq!(resp.data.validators, vec![0, 1, 2, 3]);
197 assert_eq!(resp.data.validator_aggregates, vec![vec![0, 1], vec![2, 3]]);
198
199 let roundtrip: SyncCommitteesResponse =
200 serde_json::from_str(&serde_json::to_string(&resp).unwrap()).unwrap();
201 assert_eq!(resp, roundtrip);
202 }
203
204 #[test]
205 fn serde_finality_checkpoints_response() {
206 let s = r#"{
207 "execution_optimistic": false,
208 "finalized": true,
209 "data": {
210 "previous_justified": {
211 "epoch": "10",
212 "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
213 },
214 "current_justified": {
215 "epoch": "11",
216 "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
217 },
218 "finalized": {
219 "epoch": "9",
220 "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
221 }
222 }
223 }"#;
224 let resp: FinalityCheckpointsResponse = serde_json::from_str(s).unwrap();
225 assert_eq!(resp.data.previous_justified.epoch, 10);
226 assert_eq!(resp.data.current_justified.epoch, 11);
227 assert_eq!(resp.data.finalized.epoch, 9);
228
229 let roundtrip: FinalityCheckpointsResponse =
230 serde_json::from_str(&serde_json::to_string(&resp).unwrap()).unwrap();
231 assert_eq!(resp, roundtrip);
232 }
233
234 #[test]
235 fn serde_validator_balances_response() {
236 let s = r#"{
237 "execution_optimistic": false,
238 "finalized": true,
239 "data": [
240 {
241 "index": "1",
242 "balance": "32000000000"
243 }
244 ]
245 }"#;
246 let resp: ValidatorBalancesResponse = serde_json::from_str(s).unwrap();
247 assert_eq!(resp.data.len(), 1);
248 assert_eq!(resp.data[0].index, 1);
249 assert_eq!(resp.data[0].balance, 32000000000);
250
251 let roundtrip: ValidatorBalancesResponse =
252 serde_json::from_str(&serde_json::to_string(&resp).unwrap()).unwrap();
253 assert_eq!(resp, roundtrip);
254 }
255
256 #[test]
257 fn serde_randao_response() {
258 let s = r#"{
259 "execution_optimistic": false,
260 "finalized": true,
261 "data": {
262 "randao": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
263 }
264 }"#;
265 let resp: RandaoResponse = serde_json::from_str(s).unwrap();
266 assert_eq!(
267 resp.data.randao,
268 "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
269 .parse::<B256>()
270 .unwrap()
271 );
272
273 let roundtrip: RandaoResponse =
274 serde_json::from_str(&serde_json::to_string(&resp).unwrap()).unwrap();
275 assert_eq!(resp, roundtrip);
276 }
277
278 #[test]
279 fn serde_state_root_response() {
280 let s = r#"{
281 "execution_optimistic": false,
282 "finalized": true,
283 "data": {
284 "root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
285 }
286 }"#;
287 let resp: StateRootResponse = serde_json::from_str(s).unwrap();
288 assert_eq!(
289 resp.data.root,
290 "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
291 .parse::<B256>()
292 .unwrap()
293 );
294
295 let roundtrip: StateRootResponse =
296 serde_json::from_str(&serde_json::to_string(&resp).unwrap()).unwrap();
297 assert_eq!(resp, roundtrip);
298 }
299
300 #[test]
301 fn serde_committees_defaults() {
302 let s = r#"{
303 "data": [
304 {
305 "index": "0",
306 "slot": "0",
307 "validators": []
308 }
309 ]
310 }"#;
311 let resp: CommitteesResponse = serde_json::from_str(s).unwrap();
312 assert!(!resp.execution_optimistic);
313 assert!(!resp.finalized);
314 }
315}