fix(mesh): bind Reticulum peer identity directly, not via name-matching
Two MeshPeer rows were being created for one physical Reticulum node: a radio twin (keyed by the RNS dest_hash, arch_pubkey_hex always None) and a pseudo-federation twin (keyed by the archy ed25519 pubkey, created via the generic identity-broadcast path meant for Meshcore/Meshtastic). The generic path relies on bind_federation_twins matching both twins' advert_name, but the Reticulum radio twin's display_name is deliberately never the identity text — so the two rows could never merge, and the generic send path (keyed off whichever twin the caller resolves) ended up looking up the archy pubkey's prefix in ReticulumLink's `prefix_to_hash` map, which is only ever populated with RNS dest_hash prefixes. Every send failed with "Unknown Reticulum prefix ... peer hasn't announced yet", confirmed live between two real nodes (archy-x250-exp / archy-x250-pa) that could see each other's adverts but never exchange a message. Unlike Meshcore/Meshtastic, Reticulum's ARCHY identity blob arrives in the same announce event as the destination hash, so there's no ambiguity about which peer it belongs to — bind it directly onto the RNS-hash-keyed radio peer instead of relying on name-matching. Threaded through a new `ParsedContact::arch_pubkey_hex` (None for Meshcore/Meshtastic, unchanged behavior there) so `refresh_contacts` can set it on the correct peer row without touching `bind_federation_twins`/`group_peer_twins`, which already know how to collapse twins once they share an arch_pubkey_hex. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -406,6 +406,15 @@ pub struct ParsedContact {
|
||||
/// contact has shared one.
|
||||
pub lat: Option<f64>,
|
||||
pub lon: Option<f64>,
|
||||
/// Archipelago ed25519 identity hex, when this transport carried it
|
||||
/// in-band with the contact announce itself (Reticulum only today — the
|
||||
/// RNS announce's app_data can embed an `ARCHY:n:` identity blob
|
||||
/// alongside the destination hash in the same event, so there's no
|
||||
/// ambiguity about which physical peer it belongs to). Meshcore/
|
||||
/// Meshtastic identity adverts go out on a separate channel and are
|
||||
/// correlated after the fact by `bind_federation_twins`'s advert_name
|
||||
/// matching instead, so they always leave this `None`.
|
||||
pub arch_pubkey_hex: Option<String>,
|
||||
}
|
||||
|
||||
/// Parse RESP_CONTACT (0x03) response.
|
||||
@@ -457,6 +466,7 @@ pub fn parse_contact(data: &[u8]) -> Result<ParsedContact> {
|
||||
snr: None,
|
||||
lat: None,
|
||||
lon: None,
|
||||
arch_pubkey_hex: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user