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 dns_resolved: bool,
23}
24
25impl IdentityCacheEntry {
26 fn new(
27 node_addr: NodeAddr,
28 pubkey: secp256k1::PublicKey,
29 npub: String,
30 last_seen_ms: u64,
31 dns_resolved: bool,
32 ) -> Self {
33 Self {
34 node_addr,
35 pubkey,
36 npub,
37 last_seen_ms,
38 dns_resolved,
39 }
40 }
41}
42
43#[derive(Debug, Default)]
45pub(in crate::node) struct IdentityCache {
46 entries: HashMap<[u8; 15], IdentityCacheEntry>,
47}
48
49impl IdentityCache {
50 pub(in crate::node) fn prefix_for(node_addr: &NodeAddr) -> [u8; 15] {
51 let mut prefix = [0u8; 15];
52 prefix.copy_from_slice(&node_addr.as_bytes()[0..15]);
53 prefix
54 }
55
56 pub(in crate::node) fn register(
57 &mut self,
58 node_addr: NodeAddr,
59 pubkey: secp256k1::PublicKey,
60 now_ms: u64,
61 max_entries: usize,
62 ) -> bool {
63 self.register_inner(node_addr, pubkey, now_ms, max_entries, false)
64 }
65
66 pub(in crate::node) fn register_dns_resolved(
67 &mut self,
68 node_addr: NodeAddr,
69 pubkey: secp256k1::PublicKey,
70 now_ms: u64,
71 max_entries: usize,
72 ) -> bool {
73 self.register_inner(node_addr, pubkey, now_ms, max_entries, true)
74 }
75
76 fn register_inner(
77 &mut self,
78 node_addr: NodeAddr,
79 pubkey: secp256k1::PublicKey,
80 now_ms: u64,
81 max_entries: usize,
82 dns_resolved: bool,
83 ) -> bool {
84 let prefix = Self::prefix_for(&node_addr);
85 if let Some(entry) = self.entries.get_mut(&prefix)
86 && entry.node_addr == node_addr
87 && entry.pubkey == pubkey
88 {
89 entry.last_seen_ms = now_ms;
90 entry.dns_resolved |= dns_resolved;
91 return true;
92 }
93
94 let (xonly, _) = pubkey.x_only_public_key();
95 let derived_node_addr = NodeAddr::from_pubkey(&xonly);
96 if derived_node_addr != node_addr {
97 debug!(
98 claimed_node_addr = %node_addr,
99 derived_node_addr = %derived_node_addr,
100 "Rejected identity cache entry with mismatched public key"
101 );
102 return false;
103 }
104
105 if let Some(entry) = self.entries.get_mut(&prefix)
106 && entry.node_addr == node_addr
107 {
108 entry.pubkey = pubkey;
109 entry.last_seen_ms = now_ms;
110 entry.dns_resolved |= dns_resolved;
111 return true;
112 }
113
114 let npub = encode_npub(&xonly);
115 self.entries.insert(
116 prefix,
117 IdentityCacheEntry::new(node_addr, pubkey, npub, now_ms, dns_resolved),
118 );
119 self.evict_lru(max_entries);
120 true
121 }
122
123 pub(in crate::node) fn lookup_by_prefix(
124 &mut self,
125 prefix: &[u8; 15],
126 now_ms: u64,
127 ) -> Option<(NodeAddr, secp256k1::PublicKey)> {
128 let entry = self.entries.get_mut(prefix)?;
129 entry.last_seen_ms = now_ms;
130 Some((entry.node_addr, entry.pubkey))
131 }
132
133 pub(in crate::node) fn has_prefix_for(&self, node_addr: &NodeAddr) -> bool {
134 self.entries.contains_key(&Self::prefix_for(node_addr))
135 }
136
137 pub(in crate::node) fn is_dns_resolved(&self, node_addr: &NodeAddr) -> bool {
138 self.entries
139 .get(&Self::prefix_for(node_addr))
140 .is_some_and(|entry| entry.node_addr == *node_addr && entry.dns_resolved)
141 }
142
143 pub(in crate::node) fn len(&self) -> usize {
144 self.entries.len()
145 }
146
147 pub(in crate::node) fn iter(
148 &self,
149 ) -> impl Iterator<Item = (&NodeAddr, &secp256k1::PublicKey, u64)> {
150 self.entries
151 .values()
152 .map(|entry| (&entry.node_addr, &entry.pubkey, entry.last_seen_ms))
153 }
154
155 pub(in crate::node) fn pubkey_for_node_addr(
156 &self,
157 addr: &NodeAddr,
158 ) -> Option<secp256k1::PublicKey> {
159 self.entries
160 .get(&Self::prefix_for(addr))
161 .filter(|entry| &entry.node_addr == addr)
162 .map(|entry| entry.pubkey)
163 }
164
165 pub(in crate::node) fn npub_for_node_addr(&self, addr: &NodeAddr) -> Option<String> {
166 self.entries
167 .get(&Self::prefix_for(addr))
168 .filter(|entry| &entry.node_addr == addr)
169 .map(|entry| entry.npub.clone())
170 }
171
172 fn evict_lru(&mut self, max_entries: usize) {
173 if self.entries.len() > max_entries
174 && let Some(oldest_key) = self
175 .entries
176 .iter()
177 .min_by_key(|(_, entry)| entry.last_seen_ms)
178 .map(|(key, _)| *key)
179 {
180 self.entries.remove(&oldest_key);
181 }
182 }
183}