From 4fc295d90afe20a0a5c5d282789fa2c9df397b84 Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Sat, 18 Jul 2026 15:32:04 +0000 Subject: [PATCH] node: source connection peer-identity telemetry from the peer machine The expected_peer connection-row field read the peer identity off the leg; source it from the machine's own connection-state copy instead, matching the started_at/last_activity treatment. The machine carrier holds the same identity as the leg for every connection that appears in the view: outbound legs seed both from the dialed identity, and inbound legs never rest in the connections view (the machine takes the leg at promotion), so their machine copy is unobserved. The leg accessor stays for the crypto-extraction path and retry decisions. Byte-identical. --- src/control/queries.rs | 2 +- src/node/mod.rs | 15 ++++++++++++++- src/peer/machine.rs | 9 +++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/control/queries.rs b/src/control/queries.rs index da123db..46227c2 100644 --- a/src/control/queries.rs +++ b/src/control/queries.rs @@ -1313,7 +1313,7 @@ pub fn show_connections(node: &Node) -> Value { "resend_count": node.connection_resend_count(conn.link_id()), }); - if let Some(identity) = conn.expected_identity() { + if let Some(identity) = node.connection_expected_identity(conn.link_id()) { conn_json["expected_peer"] = json!(identity.npub()); } diff --git a/src/node/mod.rs b/src/node/mod.rs index 602a80c..f711c78 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -1985,7 +1985,9 @@ impl Node { started_at_ms: self.connection_started_at(conn.link_id()), last_activity_ms: self.connection_last_activity(conn.link_id()), resend_count: self.connection_resend_count(conn.link_id()), - expected_peer: conn.expected_identity().map(|id| id.npub()), + expected_peer: self + .connection_expected_identity(conn.link_id()) + .map(|id| id.npub()), }) .collect(); @@ -2330,6 +2332,17 @@ impl Node { .map_or(0, |machine| machine.conn_last_activity()) } + /// Operator-visible expected peer identity for a pending handshake `link`, + /// read from the per-peer machine carrier (the identity's telemetry home now + /// that the leg no longer projects it). A link with no machine reports + /// `None`; every leg surfaced by `connections()` is embedded in a machine, so + /// the lookup resolves. + pub(crate) fn connection_expected_identity(&self, link: LinkId) -> Option { + self.peer_machines + .get(&link) + .and_then(|machine| machine.conn_expected_identity().copied()) + } + /// Operator-visible handshake-state string for a pending handshake `link`, /// derived from the per-peer control machine (the phase's home now that the /// leg no longer carries it). Every leg surfaced by `connections()` is diff --git a/src/peer/machine.rs b/src/peer/machine.rs index 02c5576..3b84949 100644 --- a/src/peer/machine.rs +++ b/src/peer/machine.rs @@ -587,6 +587,15 @@ impl PeerMachine { self.conn.is_timed_out(now_ms, timeout_ms) } + /// Expected peer identity of the surviving carrier — the home for the + /// operator-visible `expected_peer` now that the leg no longer projects it. + /// Outbound carries the dial identity from construction; inbound stays `None` + /// in this view (the identity learned mid-handshake never rests here, as the + /// leg is consumed by promotion within the same message-handling step). + pub(crate) fn conn_expected_identity(&self) -> Option<&PeerIdentity> { + self.conn.expected_identity() + } + /// Adopt an explicit connection-start timestamp on the carrier, so the /// surviving state keeps the leg's start provenance rather than the /// dial-time construction default.