1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
4pub enum NoxEvent {
5 NodeStarted {
6 timestamp: u64,
7 },
8
9 PacketReceived {
10 packet_id: String,
11 data: Vec<u8>,
12 size_bytes: usize,
13 },
14
15 SendPacket {
16 next_hop_peer_id: String,
17 packet_id: String,
18 data: Vec<u8>,
19 },
20
21 PayloadDecrypted {
22 packet_id: String,
23 payload: Vec<u8>,
24 },
25
26 PeerConnected {
27 peer_id: String,
28 },
29
30 PeerDisconnected {
31 peer_id: String,
32 },
33
34 RelayerRegistered {
35 address: String,
36 sphinx_key: String,
37 url: String,
38 stake: String,
39 role: u8,
41 ingress_url: Option<String>,
43 metadata_url: Option<String>,
45 },
46
47 RelayerRemoved {
48 address: String,
49 },
50
51 RelayerKeyRotated {
53 address: String,
54 new_sphinx_key: String,
55 },
56
57 RelayerRoleUpdated {
59 address: String,
60 new_role: u8,
61 },
62
63 RelayerUrlUpdated {
65 address: String,
66 new_url: String,
67 },
68
69 RelayerSlashed {
71 address: String,
72 amount: String,
73 slasher: String,
74 },
75
76 RegistryPaused {
78 by: String,
79 },
80
81 RegistryUnpaused {
83 by: String,
84 },
85
86 PacketProcessed {
87 packet_id: String,
88 duration_ms: u64,
89 },
90
91 HopTimingsRecorded {
94 packet_id: String,
95 ecdh_ns: u64,
96 key_derive_ns: u64,
97 mac_verify_ns: u64,
98 routing_decrypt_ns: u64,
99 body_decrypt_ns: u64,
100 blinding_ns: u64,
101 total_sphinx_ns: u64,
102 },
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 fn assert_json_roundtrip(event: &NoxEvent) {
110 let json = serde_json::to_string(event).expect("serialize");
111 let decoded: NoxEvent = serde_json::from_str(&json).expect("deserialize");
112 assert_eq!(*event, decoded);
113 }
114
115 fn assert_bincode_roundtrip(event: &NoxEvent) {
116 let bytes = bincode::serialize(event).expect("serialize");
117 let decoded: NoxEvent = bincode::deserialize(&bytes).expect("deserialize");
118 assert_eq!(*event, decoded);
119 }
120
121 #[test]
122 fn roundtrip_node_started() {
123 let event = NoxEvent::NodeStarted {
124 timestamp: 1709980000,
125 };
126 assert_json_roundtrip(&event);
127 assert_bincode_roundtrip(&event);
128 }
129
130 #[test]
131 fn roundtrip_packet_received() {
132 let event = NoxEvent::PacketReceived {
133 packet_id: "pkt-001".into(),
134 data: vec![0xDE, 0xAD, 0xBE, 0xEF],
135 size_bytes: 4,
136 };
137 assert_json_roundtrip(&event);
138 assert_bincode_roundtrip(&event);
139 }
140
141 #[test]
142 fn roundtrip_send_packet() {
143 let event = NoxEvent::SendPacket {
144 next_hop_peer_id: "peer-abc".into(),
145 packet_id: "pkt-002".into(),
146 data: vec![1, 2, 3],
147 };
148 assert_json_roundtrip(&event);
149 assert_bincode_roundtrip(&event);
150 }
151
152 #[test]
153 fn roundtrip_payload_decrypted() {
154 let event = NoxEvent::PayloadDecrypted {
155 packet_id: "pkt-003".into(),
156 payload: b"hello world".to_vec(),
157 };
158 assert_json_roundtrip(&event);
159 assert_bincode_roundtrip(&event);
160 }
161
162 #[test]
163 fn roundtrip_peer_connected() {
164 let event = NoxEvent::PeerConnected {
165 peer_id: "12D3KooW...".into(),
166 };
167 assert_json_roundtrip(&event);
168 assert_bincode_roundtrip(&event);
169 }
170
171 #[test]
172 fn roundtrip_peer_disconnected() {
173 let event = NoxEvent::PeerDisconnected {
174 peer_id: "12D3KooW...".into(),
175 };
176 assert_json_roundtrip(&event);
177 assert_bincode_roundtrip(&event);
178 }
179
180 #[test]
181 fn roundtrip_relayer_registered() {
182 let event = NoxEvent::RelayerRegistered {
183 address: "0x1234".into(),
184 sphinx_key: "0xabcd".into(),
185 url: "https://node.example.com".into(),
186 stake: "100000".into(),
187 role: 3,
188 ingress_url: Some("https://nox-1.hisoka.io".into()),
189 metadata_url: None,
190 };
191 assert_json_roundtrip(&event);
192 assert_bincode_roundtrip(&event);
193 }
194
195 #[test]
196 fn roundtrip_relayer_removed() {
197 let event = NoxEvent::RelayerRemoved {
198 address: "0x5678".into(),
199 };
200 assert_json_roundtrip(&event);
201 assert_bincode_roundtrip(&event);
202 }
203
204 #[test]
205 fn roundtrip_relayer_key_rotated() {
206 let event = NoxEvent::RelayerKeyRotated {
207 address: "0x1234".into(),
208 new_sphinx_key: "aabbccdd".into(),
209 };
210 assert_json_roundtrip(&event);
211 assert_bincode_roundtrip(&event);
212 }
213
214 #[test]
215 fn roundtrip_relayer_role_updated() {
216 let event = NoxEvent::RelayerRoleUpdated {
217 address: "0x1234".into(),
218 new_role: 2,
219 };
220 assert_json_roundtrip(&event);
221 assert_bincode_roundtrip(&event);
222 }
223
224 #[test]
225 fn roundtrip_relayer_url_updated() {
226 let event = NoxEvent::RelayerUrlUpdated {
227 address: "0x1234".into(),
228 new_url: "http://new-node.example.com:8080".into(),
229 };
230 assert_json_roundtrip(&event);
231 assert_bincode_roundtrip(&event);
232 }
233
234 #[test]
235 fn roundtrip_relayer_slashed() {
236 let event = NoxEvent::RelayerSlashed {
237 address: "0x1234".into(),
238 amount: "500000".into(),
239 slasher: "0x5678".into(),
240 };
241 assert_json_roundtrip(&event);
242 assert_bincode_roundtrip(&event);
243 }
244
245 #[test]
246 fn roundtrip_registry_paused() {
247 let event = NoxEvent::RegistryPaused {
248 by: "0xadmin".into(),
249 };
250 assert_json_roundtrip(&event);
251 assert_bincode_roundtrip(&event);
252 }
253
254 #[test]
255 fn roundtrip_registry_unpaused() {
256 let event = NoxEvent::RegistryUnpaused {
257 by: "0xadmin".into(),
258 };
259 assert_json_roundtrip(&event);
260 assert_bincode_roundtrip(&event);
261 }
262
263 #[test]
264 fn roundtrip_packet_processed() {
265 let event = NoxEvent::PacketProcessed {
266 packet_id: "pkt-004".into(),
267 duration_ms: 42,
268 };
269 assert_json_roundtrip(&event);
270 assert_bincode_roundtrip(&event);
271 }
272
273 #[test]
274 fn roundtrip_hop_timings_recorded() {
275 let event = NoxEvent::HopTimingsRecorded {
276 packet_id: "pkt-005".into(),
277 ecdh_ns: 100_000,
278 key_derive_ns: 50_000,
279 mac_verify_ns: 30_000,
280 routing_decrypt_ns: 20_000,
281 body_decrypt_ns: 40_000,
282 blinding_ns: 10_000,
283 total_sphinx_ns: 250_000,
284 };
285 assert_json_roundtrip(&event);
286 assert_bincode_roundtrip(&event);
287 }
288
289 #[test]
290 fn all_variants_covered() {
291 let events: Vec<NoxEvent> = vec![
294 NoxEvent::NodeStarted { timestamp: 0 },
295 NoxEvent::PacketReceived {
296 packet_id: String::new(),
297 data: vec![],
298 size_bytes: 0,
299 },
300 NoxEvent::SendPacket {
301 next_hop_peer_id: String::new(),
302 packet_id: String::new(),
303 data: vec![],
304 },
305 NoxEvent::PayloadDecrypted {
306 packet_id: String::new(),
307 payload: vec![],
308 },
309 NoxEvent::PeerConnected {
310 peer_id: String::new(),
311 },
312 NoxEvent::PeerDisconnected {
313 peer_id: String::new(),
314 },
315 NoxEvent::RelayerRegistered {
316 address: String::new(),
317 sphinx_key: String::new(),
318 url: String::new(),
319 stake: String::new(),
320 role: 0,
321 ingress_url: None,
322 metadata_url: None,
323 },
324 NoxEvent::RelayerRemoved {
325 address: String::new(),
326 },
327 NoxEvent::RelayerKeyRotated {
328 address: String::new(),
329 new_sphinx_key: String::new(),
330 },
331 NoxEvent::RelayerRoleUpdated {
332 address: String::new(),
333 new_role: 0,
334 },
335 NoxEvent::RelayerUrlUpdated {
336 address: String::new(),
337 new_url: String::new(),
338 },
339 NoxEvent::RelayerSlashed {
340 address: String::new(),
341 amount: String::new(),
342 slasher: String::new(),
343 },
344 NoxEvent::RegistryPaused { by: String::new() },
345 NoxEvent::RegistryUnpaused { by: String::new() },
346 NoxEvent::PacketProcessed {
347 packet_id: String::new(),
348 duration_ms: 0,
349 },
350 NoxEvent::HopTimingsRecorded {
351 packet_id: String::new(),
352 ecdh_ns: 0,
353 key_derive_ns: 0,
354 mac_verify_ns: 0,
355 routing_decrypt_ns: 0,
356 body_decrypt_ns: 0,
357 blinding_ns: 0,
358 total_sphinx_ns: 0,
359 },
360 ];
361 for event in &events {
362 assert_json_roundtrip(event);
363 assert_bincode_roundtrip(event);
364 }
365 }
366}