From 876bc55e2bcbe49e94418146a41bc342725401ec Mon Sep 17 00:00:00 2001 From: Jean Date: Sun, 19 Jul 2026 04:54:48 +0000 Subject: [PATCH] Deliver node-local channel directory events to the gRPC subscribe stream --- src/engine/db/mod.rs | 6 +++++- src/engine/db/tests.rs | 20 ++++++++++++++++++++ src/gossip.rs | 9 +++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/engine/db/mod.rs b/src/engine/db/mod.rs index 7e08985..dbe6316 100644 --- a/src/engine/db/mod.rs +++ b/src/engine/db/mod.rs @@ -851,8 +851,12 @@ impl EventLog { } if global { self.versions.insert(entry.origin.clone(), entry.seq); - self.notify(&entry); } + // Push every committed entry to subscribers: the gossip forwarder filters to + // Global before sending to a peer, but the gRPC directory stream wants the + // node-local channel events too (a website mirroring the account + channel + // directory, which registers/drops/founder-sets never reached before). + self.notify(&entry); self.entries.push(entry); Ok(()) } diff --git a/src/engine/db/tests.rs b/src/engine/db/tests.rs index bfafcec..d0c3aa8 100644 --- a/src/engine/db/tests.rs +++ b/src/engine/db/tests.rs @@ -458,6 +458,26 @@ assert_eq!(db.certfps("bob"), &[kept][..], "kept cert survives"); } + #[test] + fn channel_directory_events_reach_the_outbound_subscriber() { + // A gRPC directory subscriber (a website mirror) reads the outbound stream. + // Account events are Global and always flowed; channel events are Local and + // were dropped before reaching outbound, so a mirror never saw registrations. + let (tx, mut rx) = tokio::sync::broadcast::channel(64); + let mut db = Db::open(tmp("chan-sub"), "N1"); + db.scram_iterations = 4096; + db.set_outbound(tx); + db.register("alice", "pw", None).unwrap(); + db.register_channel("#c", "alice").unwrap(); + let mut saw_channel = false; + while let Ok(entry) = rx.try_recv() { + if matches!(entry.event(), Event::ChannelRegistered { name, .. } if name == "#c") { + saw_channel = true; + } + } + assert!(saw_channel, "channel registration must reach the outbound directory stream"); + } + #[test] fn compaction_preserves_channel_last_used_and_levels() { let p = tmp("compact-chan"); diff --git a/src/gossip.rs b/src/gossip.rs index 43e2db8..224128c 100644 --- a/src/gossip.rs +++ b/src/gossip.rs @@ -13,6 +13,8 @@ use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer, ServerName} use tokio_rustls::rustls::{self, ClientConfig, RootCertStore, ServerConfig}; use tokio_rustls::{TlsAcceptor, TlsConnector}; +use crate::engine::db::Scope; + use crate::config::{Gossip, Peer, Tls}; use crate::engine::db::LogEntry; use crate::engine::Engine; @@ -205,6 +207,13 @@ where loop { match rx.recv().await { Ok(entry) => { + // Only global (account/identity) state replicates to peers; + // channel state is node-local, so never forward it — the + // outbound stream now also carries local events for the gRPC + // directory subscriber. + if entry.event().scope() != Scope::Global { + continue; + } if send(&tx, &Msg::Entry { entry: Box::new(entry) }).await.is_err() { break; }