use super::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NodeDeliveredPacket {
pub source_node_addr: NodeAddr,
pub source_npub: Option<String>,
pub destination: FipsAddress,
pub packet: Vec<u8>,
}
#[derive(Debug, Clone)]
struct IdentityCacheEntry {
node_addr: NodeAddr,
pubkey: secp256k1::PublicKey,
npub: String,
last_seen_ms: u64,
}
impl IdentityCacheEntry {
fn new(
node_addr: NodeAddr,
pubkey: secp256k1::PublicKey,
npub: String,
last_seen_ms: u64,
) -> Self {
Self {
node_addr,
pubkey,
npub,
last_seen_ms,
}
}
}
#[derive(Debug, Default)]
pub(in crate::node) struct IdentityCache {
entries: HashMap<[u8; 15], IdentityCacheEntry>,
}
impl IdentityCache {
pub(in crate::node) fn prefix_for(node_addr: &NodeAddr) -> [u8; 15] {
let mut prefix = [0u8; 15];
prefix.copy_from_slice(&node_addr.as_bytes()[0..15]);
prefix
}
pub(in crate::node) fn register(
&mut self,
node_addr: NodeAddr,
pubkey: secp256k1::PublicKey,
now_ms: u64,
max_entries: usize,
) -> bool {
let prefix = Self::prefix_for(&node_addr);
if let Some(entry) = self.entries.get(&prefix)
&& entry.node_addr == node_addr
&& entry.pubkey == pubkey
{
return true;
}
let (xonly, _) = pubkey.x_only_public_key();
let derived_node_addr = NodeAddr::from_pubkey(&xonly);
if derived_node_addr != node_addr {
debug!(
claimed_node_addr = %node_addr,
derived_node_addr = %derived_node_addr,
"Rejected identity cache entry with mismatched public key"
);
return false;
}
if let Some(entry) = self.entries.get_mut(&prefix)
&& entry.node_addr == node_addr
{
entry.pubkey = pubkey;
entry.last_seen_ms = now_ms;
return true;
}
let npub = encode_npub(&xonly);
self.entries.insert(
prefix,
IdentityCacheEntry::new(node_addr, pubkey, npub, now_ms),
);
self.evict_lru(max_entries);
true
}
pub(in crate::node) fn lookup_by_prefix(
&mut self,
prefix: &[u8; 15],
now_ms: u64,
) -> Option<(NodeAddr, secp256k1::PublicKey)> {
let entry = self.entries.get_mut(prefix)?;
entry.last_seen_ms = now_ms;
Some((entry.node_addr, entry.pubkey))
}
pub(in crate::node) fn has_prefix_for(&self, node_addr: &NodeAddr) -> bool {
self.entries.contains_key(&Self::prefix_for(node_addr))
}
pub(in crate::node) fn len(&self) -> usize {
self.entries.len()
}
pub(in crate::node) fn iter(
&self,
) -> impl Iterator<Item = (&NodeAddr, &secp256k1::PublicKey, u64)> {
self.entries
.values()
.map(|entry| (&entry.node_addr, &entry.pubkey, entry.last_seen_ms))
}
pub(in crate::node) fn pubkey_for_node_addr(
&self,
addr: &NodeAddr,
) -> Option<secp256k1::PublicKey> {
self.entries
.get(&Self::prefix_for(addr))
.filter(|entry| &entry.node_addr == addr)
.map(|entry| entry.pubkey)
}
pub(in crate::node) fn npub_for_node_addr(&self, addr: &NodeAddr) -> Option<String> {
self.entries
.get(&Self::prefix_for(addr))
.filter(|entry| &entry.node_addr == addr)
.map(|entry| entry.npub.clone())
}
fn evict_lru(&mut self, max_entries: usize) {
if self.entries.len() > max_entries
&& let Some(oldest_key) = self
.entries
.iter()
.min_by_key(|(_, entry)| entry.last_seen_ms)
.map(|(key, _)| *key)
{
self.entries.remove(&oldest_key);
}
}
#[cfg(test)]
pub(in crate::node) fn insert_for_test(
&mut self,
node_addr: NodeAddr,
pubkey: secp256k1::PublicKey,
npub: String,
last_seen_ms: u64,
) {
self.entries.insert(
Self::prefix_for(&node_addr),
IdentityCacheEntry::new(node_addr, pubkey, npub, last_seen_ms),
);
}
}