fips_core/node/
identity_cache.rs1use super::*;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct NodeDeliveredPacket {
6 pub source_node_addr: NodeAddr,
8 pub source_npub: Option<String>,
10 pub destination: FipsAddress,
12 pub packet: Vec<u8>,
14}
15
16#[derive(Debug, Clone)]
17struct IdentityCacheEntry {
18 node_addr: NodeAddr,
19 pubkey: secp256k1::PublicKey,
20 npub: String,
21 last_seen_ms: u64,
22}
23
24impl IdentityCacheEntry {
25 fn new(
26 node_addr: NodeAddr,
27 pubkey: secp256k1::PublicKey,
28 npub: String,
29 last_seen_ms: u64,
30 ) -> Self {
31 Self {
32 node_addr,
33 pubkey,
34 npub,
35 last_seen_ms,
36 }
37 }
38}
39
40#[derive(Debug, Default)]
42pub(in crate::node) struct IdentityCache {
43 entries: HashMap<[u8; 15], IdentityCacheEntry>,
44}
45
46impl IdentityCache {
47 pub(in crate::node) fn prefix_for(node_addr: &NodeAddr) -> [u8; 15] {
48 let mut prefix = [0u8; 15];
49 prefix.copy_from_slice(&node_addr.as_bytes()[0..15]);
50 prefix
51 }
52
53 pub(in crate::node) fn register(
54 &mut self,
55 node_addr: NodeAddr,
56 pubkey: secp256k1::PublicKey,
57 now_ms: u64,
58 max_entries: usize,
59 ) -> bool {
60 let prefix = Self::prefix_for(&node_addr);
61 if let Some(entry) = self.entries.get(&prefix)
62 && entry.node_addr == node_addr
63 && entry.pubkey == pubkey
64 {
65 return true;
66 }
67
68 let (xonly, _) = pubkey.x_only_public_key();
69 let derived_node_addr = NodeAddr::from_pubkey(&xonly);
70 if derived_node_addr != node_addr {
71 debug!(
72 claimed_node_addr = %node_addr,
73 derived_node_addr = %derived_node_addr,
74 "Rejected identity cache entry with mismatched public key"
75 );
76 return false;
77 }
78
79 if let Some(entry) = self.entries.get_mut(&prefix)
80 && entry.node_addr == node_addr
81 {
82 entry.pubkey = pubkey;
83 entry.last_seen_ms = now_ms;
84 return true;
85 }
86
87 let npub = encode_npub(&xonly);
88 self.entries.insert(
89 prefix,
90 IdentityCacheEntry::new(node_addr, pubkey, npub, now_ms),
91 );
92 self.evict_lru(max_entries);
93 true
94 }
95
96 pub(in crate::node) fn lookup_by_prefix(
97 &mut self,
98 prefix: &[u8; 15],
99 now_ms: u64,
100 ) -> Option<(NodeAddr, secp256k1::PublicKey)> {
101 let entry = self.entries.get_mut(prefix)?;
102 entry.last_seen_ms = now_ms;
103 Some((entry.node_addr, entry.pubkey))
104 }
105
106 pub(in crate::node) fn has_prefix_for(&self, node_addr: &NodeAddr) -> bool {
107 self.entries.contains_key(&Self::prefix_for(node_addr))
108 }
109
110 pub(in crate::node) fn len(&self) -> usize {
111 self.entries.len()
112 }
113
114 pub(in crate::node) fn iter(
115 &self,
116 ) -> impl Iterator<Item = (&NodeAddr, &secp256k1::PublicKey, u64)> {
117 self.entries
118 .values()
119 .map(|entry| (&entry.node_addr, &entry.pubkey, entry.last_seen_ms))
120 }
121
122 pub(in crate::node) fn pubkey_for_node_addr(
123 &self,
124 addr: &NodeAddr,
125 ) -> Option<secp256k1::PublicKey> {
126 self.entries
127 .get(&Self::prefix_for(addr))
128 .filter(|entry| &entry.node_addr == addr)
129 .map(|entry| entry.pubkey)
130 }
131
132 pub(in crate::node) fn npub_for_node_addr(&self, addr: &NodeAddr) -> Option<String> {
133 self.entries
134 .get(&Self::prefix_for(addr))
135 .filter(|entry| &entry.node_addr == addr)
136 .map(|entry| entry.npub.clone())
137 }
138
139 fn evict_lru(&mut self, max_entries: usize) {
140 if self.entries.len() > max_entries
141 && let Some(oldest_key) = self
142 .entries
143 .iter()
144 .min_by_key(|(_, entry)| entry.last_seen_ms)
145 .map(|(key, _)| *key)
146 {
147 self.entries.remove(&oldest_key);
148 }
149 }
150
151 #[cfg(test)]
152 pub(in crate::node) fn insert_for_test(
153 &mut self,
154 node_addr: NodeAddr,
155 pubkey: secp256k1::PublicKey,
156 npub: String,
157 last_seen_ms: u64,
158 ) {
159 self.entries.insert(
160 Self::prefix_for(&node_addr),
161 IdentityCacheEntry::new(node_addr, pubkey, npub, last_seen_ms),
162 );
163 }
164}