use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum NoxEvent {
NodeStarted {
timestamp: u64,
},
PacketReceived {
packet_id: String,
data: Vec<u8>,
size_bytes: usize,
},
SendPacket {
next_hop_peer_id: String,
packet_id: String,
data: Vec<u8>,
},
PayloadDecrypted {
packet_id: String,
payload: Vec<u8>,
},
PeerConnected {
peer_id: String,
},
PeerDisconnected {
peer_id: String,
},
RelayerRegistered {
address: String,
sphinx_key: String,
url: String,
stake: String,
role: u8,
ingress_url: Option<String>,
metadata_url: Option<String>,
},
RelayerRemoved {
address: String,
},
RelayerKeyRotated {
address: String,
new_sphinx_key: String,
},
RelayerRoleUpdated {
address: String,
new_role: u8,
},
RelayerUrlUpdated {
address: String,
new_url: String,
},
RelayerSlashed {
address: String,
amount: String,
slasher: String,
},
RegistryPaused {
by: String,
},
RegistryUnpaused {
by: String,
},
PacketProcessed {
packet_id: String,
duration_ms: u64,
},
HopTimingsRecorded {
packet_id: String,
ecdh_ns: u64,
key_derive_ns: u64,
mac_verify_ns: u64,
routing_decrypt_ns: u64,
body_decrypt_ns: u64,
blinding_ns: u64,
total_sphinx_ns: u64,
},
}
#[cfg(test)]
mod tests {
use super::*;
fn assert_json_roundtrip(event: &NoxEvent) {
let json = serde_json::to_string(event).expect("serialize");
let decoded: NoxEvent = serde_json::from_str(&json).expect("deserialize");
assert_eq!(*event, decoded);
}
fn assert_bincode_roundtrip(event: &NoxEvent) {
let bytes = bincode::serialize(event).expect("serialize");
let decoded: NoxEvent = bincode::deserialize(&bytes).expect("deserialize");
assert_eq!(*event, decoded);
}
#[test]
fn roundtrip_node_started() {
let event = NoxEvent::NodeStarted {
timestamp: 1709980000,
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn roundtrip_packet_received() {
let event = NoxEvent::PacketReceived {
packet_id: "pkt-001".into(),
data: vec![0xDE, 0xAD, 0xBE, 0xEF],
size_bytes: 4,
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn roundtrip_send_packet() {
let event = NoxEvent::SendPacket {
next_hop_peer_id: "peer-abc".into(),
packet_id: "pkt-002".into(),
data: vec![1, 2, 3],
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn roundtrip_payload_decrypted() {
let event = NoxEvent::PayloadDecrypted {
packet_id: "pkt-003".into(),
payload: b"hello world".to_vec(),
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn roundtrip_peer_connected() {
let event = NoxEvent::PeerConnected {
peer_id: "12D3KooW...".into(),
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn roundtrip_peer_disconnected() {
let event = NoxEvent::PeerDisconnected {
peer_id: "12D3KooW...".into(),
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn roundtrip_relayer_registered() {
let event = NoxEvent::RelayerRegistered {
address: "0x1234".into(),
sphinx_key: "0xabcd".into(),
url: "https://node.example.com".into(),
stake: "100000".into(),
role: 3,
ingress_url: Some("https://nox-1.hisoka.io".into()),
metadata_url: None,
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn roundtrip_relayer_removed() {
let event = NoxEvent::RelayerRemoved {
address: "0x5678".into(),
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn roundtrip_relayer_key_rotated() {
let event = NoxEvent::RelayerKeyRotated {
address: "0x1234".into(),
new_sphinx_key: "aabbccdd".into(),
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn roundtrip_relayer_role_updated() {
let event = NoxEvent::RelayerRoleUpdated {
address: "0x1234".into(),
new_role: 2,
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn roundtrip_relayer_url_updated() {
let event = NoxEvent::RelayerUrlUpdated {
address: "0x1234".into(),
new_url: "http://new-node.example.com:8080".into(),
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn roundtrip_relayer_slashed() {
let event = NoxEvent::RelayerSlashed {
address: "0x1234".into(),
amount: "500000".into(),
slasher: "0x5678".into(),
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn roundtrip_registry_paused() {
let event = NoxEvent::RegistryPaused {
by: "0xadmin".into(),
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn roundtrip_registry_unpaused() {
let event = NoxEvent::RegistryUnpaused {
by: "0xadmin".into(),
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn roundtrip_packet_processed() {
let event = NoxEvent::PacketProcessed {
packet_id: "pkt-004".into(),
duration_ms: 42,
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn roundtrip_hop_timings_recorded() {
let event = NoxEvent::HopTimingsRecorded {
packet_id: "pkt-005".into(),
ecdh_ns: 100_000,
key_derive_ns: 50_000,
mac_verify_ns: 30_000,
routing_decrypt_ns: 20_000,
body_decrypt_ns: 40_000,
blinding_ns: 10_000,
total_sphinx_ns: 250_000,
};
assert_json_roundtrip(&event);
assert_bincode_roundtrip(&event);
}
#[test]
fn all_variants_covered() {
let events: Vec<NoxEvent> = vec![
NoxEvent::NodeStarted { timestamp: 0 },
NoxEvent::PacketReceived {
packet_id: String::new(),
data: vec![],
size_bytes: 0,
},
NoxEvent::SendPacket {
next_hop_peer_id: String::new(),
packet_id: String::new(),
data: vec![],
},
NoxEvent::PayloadDecrypted {
packet_id: String::new(),
payload: vec![],
},
NoxEvent::PeerConnected {
peer_id: String::new(),
},
NoxEvent::PeerDisconnected {
peer_id: String::new(),
},
NoxEvent::RelayerRegistered {
address: String::new(),
sphinx_key: String::new(),
url: String::new(),
stake: String::new(),
role: 0,
ingress_url: None,
metadata_url: None,
},
NoxEvent::RelayerRemoved {
address: String::new(),
},
NoxEvent::RelayerKeyRotated {
address: String::new(),
new_sphinx_key: String::new(),
},
NoxEvent::RelayerRoleUpdated {
address: String::new(),
new_role: 0,
},
NoxEvent::RelayerUrlUpdated {
address: String::new(),
new_url: String::new(),
},
NoxEvent::RelayerSlashed {
address: String::new(),
amount: String::new(),
slasher: String::new(),
},
NoxEvent::RegistryPaused { by: String::new() },
NoxEvent::RegistryUnpaused { by: String::new() },
NoxEvent::PacketProcessed {
packet_id: String::new(),
duration_ms: 0,
},
NoxEvent::HopTimingsRecorded {
packet_id: String::new(),
ecdh_ns: 0,
key_derive_ns: 0,
mac_verify_ns: 0,
routing_decrypt_ns: 0,
body_decrypt_ns: 0,
blinding_ns: 0,
total_sphinx_ns: 0,
},
];
for event in &events {
assert_json_roundtrip(event);
assert_bincode_roundtrip(event);
}
}
}