From 81c25b15fb5ae7078452d8b2af50423921c41a55 Mon Sep 17 00:00:00 2001 From: Taksh Date: Mon, 17 Aug 2026 08:51:54 +0530 Subject: [PATCH] fix(geohash): publish currentGeohash writes to the threads that read it GeohashRepository synchronizes every accessor that touches its shared maps - eighteen of them - but currentGeohash is a plain var with two unsynchronized accessors, and it is written from the UI thread when the user picks a channel while Nostr handler and timer threads read it. Several of those reads happen inside the @Synchronized methods (refreshGeohashPeople, updateParticipant, displayNameForNostrPubkey), and holding the lock on the read side buys nothing when the write side never takes it: there is no happens-before edge, so a stale value can persist. Two ways that shows up: startGeoParticipantsTimer loops `while (repo.getCurrentGeohash() != null)` and keeps refreshing a channel the user has left, and displayNameForNostrPubkey derives the identity for the wrong geohash when deciding whether a pubkey is us. Synchronize the two accessors, matching the rest of the class. NotificationManager keeps the same state @Volatile for this reason. --- .../java/com/bitchat/android/nostr/GeohashRepository.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/bitchat/android/nostr/GeohashRepository.kt b/app/src/main/java/com/bitchat/android/nostr/GeohashRepository.kt index 50c72cd45..49b147db3 100644 --- a/app/src/main/java/com/bitchat/android/nostr/GeohashRepository.kt +++ b/app/src/main/java/com/bitchat/android/nostr/GeohashRepository.kt @@ -64,10 +64,17 @@ class GeohashRepository( // peerID alias -> nostr pubkey mapping for geohash DMs and temp aliases private val nostrKeyMapping: MutableMap = mutableMapOf() - // Current geohash in view + // Current geohash in view. Written from the UI thread when the user picks + // a channel and read from Nostr handler and timer threads - including from + // the @Synchronized methods below, which only see a published write if the + // write itself is synchronized. NotificationManager marks its copy of this + // state @Volatile for the same reason. private var currentGeohash: String? = null + @Synchronized fun setCurrentGeohash(geo: String?) { currentGeohash = geo } + + @Synchronized fun getCurrentGeohash(): String? = currentGeohash @Synchronized