nym_types/
monitoring.rs

1use nym_crypto::asymmetric::ed25519::{PrivateKey, PublicKey, Signature};
2use nym_mixnet_contract_common::NodeId;
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5use std::{collections::HashSet, sync::LazyLock, time::SystemTime};
6use utoipa::ToSchema;
7
8static NETWORK_MONITORS: LazyLock<HashSet<String>> = LazyLock::new(|| {
9    let mut nm = HashSet::new();
10    nm.insert("5VsPyLbsBCq9PAMWmjKkToteVAKNabNqex6QwDf5fWzt".to_string());
11    nm
12});
13
14#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, ToSchema)]
15pub struct NodeResult {
16    #[schema(value_type = u32)]
17    pub node_id: NodeId,
18    pub identity: String,
19    pub reliability: u8,
20}
21
22impl NodeResult {
23    pub fn new(node_id: NodeId, identity: String, reliability: u8) -> Self {
24        NodeResult {
25            node_id,
26            identity,
27            reliability,
28        }
29    }
30}
31
32#[derive(Serialize, Deserialize, JsonSchema)]
33#[serde(untagged)]
34pub enum MonitorResults {
35    Mixnode(Vec<NodeResult>),
36    Gateway(Vec<NodeResult>),
37}
38
39#[derive(Serialize, Deserialize, JsonSchema, ToSchema)]
40pub struct MonitorMessage {
41    results: Vec<NodeResult>,
42    signature: String,
43    signer: String,
44    timestamp: i64,
45}
46
47impl MonitorMessage {
48    fn message_to_sign(results: &[NodeResult], timestamp: i64) -> Vec<u8> {
49        let mut msg = serde_json::to_vec(results).unwrap_or_default();
50        msg.extend_from_slice(&timestamp.to_le_bytes());
51        msg
52    }
53
54    pub fn timely(&self) -> bool {
55        let now = SystemTime::now()
56            .duration_since(SystemTime::UNIX_EPOCH)
57            .expect("Time went backwards")
58            .as_secs() as i64;
59
60        now - self.timestamp < 5
61    }
62
63    pub fn new(results: Vec<NodeResult>, private_key: &PrivateKey) -> Self {
64        let timestamp = SystemTime::now()
65            .duration_since(SystemTime::UNIX_EPOCH)
66            .expect("Time went backwards")
67            .as_secs() as i64;
68
69        let msg = Self::message_to_sign(&results, timestamp);
70        let signature = private_key.sign(&msg);
71        let public_key = private_key.public_key();
72
73        MonitorMessage {
74            results,
75            signature: signature.to_base58_string(),
76            signer: public_key.to_base58_string(),
77            timestamp,
78        }
79    }
80
81    pub fn is_in_allowed(&self) -> bool {
82        NETWORK_MONITORS.contains(&self.signer)
83    }
84
85    pub fn results(&self) -> &[NodeResult] {
86        &self.results
87    }
88
89    pub fn verify(&self) -> bool {
90        let msg = Self::message_to_sign(&self.results, self.timestamp);
91
92        let signature = match Signature::from_base58_string(&self.signature) {
93            Ok(sig) => sig,
94            Err(_) => return false,
95        };
96
97        PublicKey::from_base58_string(&self.signer)
98            .map(|pk| pk.verify(msg, &signature).is_ok())
99            .unwrap_or(false)
100    }
101}