Relais des canaux geohash : mise à jour des listes sur iOS et Android
État au 26/10/2026, d'après les sources publiques de BitChat (dépôts permissionlesstech/bitchat,
bitchat-android et georelays) et des mesures faites avec examples/geohash_map.rs.
En bref
- Les messages d'un canal geohash ne vont que sur les 5 relais les plus proches du centre de la cellule. Ces relais sont pris dans une liste de relais géolocalisés.
- iOS et Android ne lisent pas la même liste. iOS lit une copie relue à la main, mise à jour irrégulièrement. Android lit la liste brute, régénérée chaque jour.
- Les deux apps peuvent donc choisir des relais différents pour le même canal. Un message posté depuis Android peut ne jamais atteindre un utilisateur iOS du même canal, et inversement.
- La liste d'iOS garde aussi des relais morts que la liste brute a déjà retirés.
1. D'où vient la liste : le dépôt georelays
Le dépôt permissionlesstech/georelays produit le
fichier nostr_relays.csv (une ligne hôte,latitude,longitude par relais). Une GitHub Action le
régénère chaque jour, en trois étapes :
| Étape | Outil | Ce qui est fait |
|---|---|---|
| Découverte | nostr_relay_discovery.py | Parcours du réseau Nostr à partir d'un relais de départ, via les listes de contacts (kind 3) et de relais (kind 10002). Chaque candidat est testé par un REQ. |
| Filtre BitChat | filter_bitchat_relays.sh (nak) | Seuls les relais qui acceptent de lire et d'écrire un événement kind 20000 sont gardés. Le test répond aux challenges NIP-42. |
| Localisation | relays_geo_lookup.py | Coordonnées estimées d'après l'adresse IPv4 du relais. |
Deux limites découlent de cette méthode :
- Positions approximatives. La géolocalisation par IP renvoie souvent le centre d'une ville. Beaucoup de relais partagent donc exactement les mêmes coordonnées : par exemple 6 relais au même point de Londres (51.5072, -0.1276) et plusieurs au centre de Paris. Cela crée des égalités dans le classement par distance.
- Relais inutilisables par l'app. Le filtre s'authentifie (NIP-42), mais l'app ne le fait pas. Un relais qui exige l'authentification passe donc le filtre tout en restant inutilisable par l'app.
2. iOS : une copie relue, mise à jour par PR
Le dépôt de l'app iOS garde sa propre copie, relays/online_relays_gps.csv.
- Le workflow
fetch_georelays.ymltourne chaque dimanche à 06:00 UTC. Il récupèrenostr_relays.csven amont (à un commit figé), puis le fait vérifier parscripts/validate_georelays.py: encodage, schéma, taille, hôtes enwss, coordonnées, doublons, ampleur de l'écart avec la version précédente. - S'il y a des changements, le workflow ouvre une PR qui n'est pas fusionnée automatiquement. Elle n'entre en vigueur que lorsqu'un mainteneur la relit et la fusionne.
- Dernière mise à jour fusionnée : 26/07/2026. Au 26/10/2026, la liste iOS a donc environ trois mois de retard sur la liste en amont.
Dans l'app (GeoRelayDirectory.swift, TransportConfig.swift) :
| Paramètre | Valeur |
|---|---|
| Source téléchargée | https://raw.githubusercontent.com/permissionlesstech/bitchat/refs/heads/main/relays/online_relays_gps.csv |
| Fréquence de téléchargement | 24 h |
| Vérification de fraîcheur | toutes les heures |
| Nouvel essai après un échec | de 1 min jusqu'à 1 h maximum |
| Repli | cache local (georelays_cache_v2.csv), puis CSV embarqué dans l'app |
| Réseau | via Tor si Tor est activé ; si Tor n'est pas prêt, le téléchargement est sauté (pour ne pas exposer l'IP), et l'app garde son cache |
3. Android : la liste brute, directement
Dans RelayDirectory.kt :
| Paramètre | Valeur |
|---|---|
| Source téléchargée | https://raw.githubusercontent.com/permissionlesstech/georelays/refs/heads/main/nostr_relays.csv, la liste en amont, sans relecture |
| Fréquence de téléchargement | quand les données ont plus de 24 h |
| Repli | CSV embarqué dans l'app (assets) |
| Réseau | non vérifié |
4. Récapitulatif
| iOS | Android | |
|---|---|---|
| Liste utilisée | copie relue dans bitchat | georelays en amont |
| Rythme réel des changements | à chaque PR fusionnée (dernière le 26/07/2026) | quotidien |
| Contrôle humain | oui | non |
| Retard au 26/10/2026 | environ 3 mois | environ 1 jour |
| Égalité pour la 5ᵉ place | départagée par nom d'hôte | ordre du CSV conservé |
5. Conséquences pour les canaux
5.1 Les deux apps ne se retrouvent pas toujours sur les mêmes relais
Chaque app prend les 5 relais les plus proches dans sa propre liste. Dès que les deux listes diffèrent près d'une cellule, les deux sélections diffèrent aussi. Un canal n'est alors réellement partagé que par les relais communs aux deux sélections.
Mesures du 26/10/2026 (geohash_map, colonne « rang iOS / rang Android », - = non choisi) :
#u09tv (Paris) : 8 relais au total, 2 seulement communs aux deux apps.
| Relais | iOS | Android | État |
|---|---|---|---|
| nostr.wild-vibes.ts.net | 1 | 1 | utilisable |
| relay-fra.zombi.cloudrodion.com | 2 | 2 | pas de réponse en 8 s |
| relay.mmwaves.de | 4 | - | utilisable (envoie des challenges AUTH) |
| nostr-relay.xbytez.io (Lille) | - | 3 | utilisable |
| r.senx.io (Lille) | - | 4 | pas de réponse en 8 s |
| relay.noeudlibre.fr (Lille) | - | 5 | utilisable, seul relais avec du trafic (26 à 30 événements récents) |
| relay.cypherflow.ai | 3 | - | mort : certificat d'un émetteur inconnu |
| treuzkas.branruz.com | 5 | - | mort : certificat émis pour un autre nom |
Ce qu'on en tire :
- iOS publie sur 2 relais morts, qui ont déjà disparu de la liste en amont.
- Il ne reste à iOS qu'un seul relais commun et opérationnel avec Android (
wild-vibes). - Le seul relais où le canal est actif n'est choisi que par Android.
#u1 (Pays-Bas) : 9 relais au total, 3 communs. Les relais les plus actifs
(nostr.stakey.net avec 104 événements, relay.mccormick.cx avec 123, test.relays.nuts.cash
avec 98) sont choisis surtout, ou uniquement, par Android.
5.2 Effets visibles pour les utilisateurs
- Messages qui n'arrivent pas d'une plateforme à l'autre : un message ne passe que par les relais choisis par les deux apps. S'ils sont en panne ou inexistants, le canal est coupé en deux.
- Présence incomplète : les signaux de présence (kind 20001) suivent le même chemin. La liste « people » d'un utilisateur iOS peut ne pas montrer certains utilisateurs Android, et inversement.
- Variation dans le temps : la liste Android change chaque jour, celle d'iOS par à-coups. La partie commune aux deux sélections change donc sans que les utilisateurs touchent à rien.
- Pas de rattrapage : les kinds 20000/20001 sont éphémères. Les relais ne les stockent généralement pas, donc un message qui n'a pas atteint un relais au moment de l'envoi est perdu pour ceux qui lisent ce relais.
5.3 Effets aggravants
- Égalités de distance : avec des coordonnées identiques, iOS et Android départagent différemment la 5ᵉ place. Les sélections peuvent donc différer même avec la même liste.
- Relais exigeant NIP-42 : présents dans la liste, mais inutilisables par l'app (voir §1).
- Pas de remplacement : une app ne remplace pas un relais mort par le suivant. Un relais mort réduit donc directement le nombre de relais effectifs du canal.
6. Ce que font nos outils
examples/geohash_map.rsaffiche, pour un geohash, la sélection iOS et la sélection Android, avec le rang de chaque relais dans chacune et le résultat d'un test de lecture du canal. Le modeoverlayproduit une carte. Les relais en panne durable (certificat, DNS, connexion refusée, HTTP 4xx) sont écartés par défaut ;--no-drop-deadles garde.examples/geohash_bot.rslit les deux listes (--relays-csv,--android-csv) et utilise l'union des deux sélections, pour atteindre les utilisateurs des deux plateformes. Il écarte aussi par défaut les relais en panne durable.
Pour reproduire les mesures :
curl -sLO https://raw.githubusercontent.com/permissionlesstech/bitchat/main/relays/online_relays_gps.csv
curl -sLO https://raw.githubusercontent.com/permissionlesstech/georelays/main/nostr_relays.csv
cargo run --example geohash_map -- u09tv overlay7. Pistes (pour BitChat, hors de ce crate)
- Faire lire la même liste aux deux apps : soit Android passe sur la copie relue, soit iOS accepte la liste en amont validée automatiquement.
- Fusionner plus souvent les PR hebdomadaires, ou les fusionner automatiquement quand le validateur ne signale qu'un écart faible.
- Aligner les deux apps sur la même règle de départage des égalités.
- Retirer de la liste les relais qui exigent NIP-42, puisque l'app ne fait pas d'authentification. Le filtre en amont pourrait tester sans authentification.
Sources
- iOS :
bitchat/Nostr/GeoRelayDirectory.swift,bitchat/Services/TransportConfig.swift,.github/workflows/fetch_georelays.yml,.github/workflows/validate_georelays.yml(dépôtpermissionlesstech/bitchat). Historique derelays/online_relays_gps.csv: derniers commits le 31/05, 07/06, 14/06, 21/06 et 26/07/2026. - Android :
app/src/main/java/com/bitchat/android/nostr/RelayDirectory.kt(dépôtpermissionlesstech/bitchat-android). - Liste en amont : README et scripts du dépôt
permissionlesstech/georelays(dernière mise à jour le 25/10/2026). - Mesures :
geohash_map, le 26/10/2026. L'état des relais change d'un jour à l'autre.
Activity
2When was the file currently served for download last updated?
The data dates from 2026-07-25 at 08:42 UTC. The online file (SHA-256 81152310…) is byte-for-byte identical to nostr_relays.csv in upstream georelays commit eb5fc78. It is a snapshot of relay status at that moment.
It was published to main on 2026-07-26 at 06:54 UTC by bitchat commit fb8fe397. That was the last successful sync, made just before updates moved to reviewed pull requests (#1436, the same day).
The file users download is therefore about 3 months old (94 days). Over that time, georelays has kept publishing a new snapshot almost every day; the most recent is from 2026-10-26.
Risk: the margin is shrinking
The app compares each new file with the one it already has, here the CSV bundled on 2026-07-26. With the current upstream file, 175 identical entries are retained against 163 required: only 12 entries of margin remain. If the merge is delayed further and relays keep changing, a future file could fall below 50%. v1.8.0 would then reject it indefinitely, retrying periodically, until a new app release ships.
So #1738 or the automation branch should be merged soon, and issue #1724 then closed. The automation should also be allowed to create pull requests; otherwise the blockage will come back every week.
Date de mise à jour du fichier actuellement proposé au téléchargement?
Les données datent du 25/07/2026 à 08:42 UTC. Le fichier en ligne (SHA-256 81152310…) est identique, octet pour octet, au nostr_relays.csv du commit amont georelays eb5fc78. C'est le relevé de l'état des relais à ce moment-là.
Il a été publié sur main le 26/07/2026 à 06:54 UTC, par le commit bitchat fb8fe397. C'est la dernière synchronisation réussie, faite juste avant le passage aux PR soumises à relecture (#1436, le même jour).
Le fichier que téléchargent les utilisateurs a donc environ 3 mois (94 jours). Pendant ce temps, georelays a continué à publier un nouveau relevé presque chaque jour : le plus récent date du 26/10/2026.
Risque : la marge diminue
L'app compare chaque nouveau fichier à celui qu'elle a déjà, ici le CSV embarqué du 26/07. Avec le fichier amont actuel, 175 entrées identiques sont conservées pour 163 exigées : il ne reste que 12 entrées de marge. Si la fusion tarde encore et que les relais changent davantage, un futur fichier pourrait passer sous 50 %. La v1.8.0 le refuserait alors indéfiniment, en réessayant régulièrement, jusqu'à une nouvelle version de l'app.
Il faut donc fusionner rapidement la #1738 ou la branche d'automatisation, puis fermer l'issue #1724. Il faudrait aussi donner à l'automatisation le droit de créer des PR, sinon le blocage reviendra chaque semaine.
Geohash channel relays: how the lists are updated on iOS and Android
As of 2026-10-26, based on BitChat's public sources (repositories
permissionlesstech/bitchat,bitchat-androidandgeorelays) and on measurements made withexamples/geohash_map.rs.Summary
1. Where the list comes from: the
georelaysrepositoryThe permissionlesstech/georelays repository produces
nostr_relays.csv(onehost,latitude,longitudeline per relay). A GitHub Action regenerates it every day, in three steps:nostr_relay_discovery.pyREQ.filter_bitchat_relays.sh(nak)relays_geo_lookup.pyThis method has two limits:
2. iOS: a reviewed copy, updated through PRs
The iOS app's repository keeps its own copy,
relays/online_relays_gps.csv.fetch_georelays.ymlworkflow runs every Sunday at 06:00 UTC. It fetches the upstreamnostr_relays.csv(at a pinned commit), then has it checked byscripts/validate_georelays.py: encoding, schema, size,wsshosts, coordinates, duplicates, and how far it differs from the previous version.In the app (
GeoRelayDirectory.swift,TransportConfig.swift):https://raw.githubusercontent.com/permissionlesstech/bitchat/refs/heads/main/relays/online_relays_gps.csvgeorelays_cache_v2.csv), then the CSV bundled with the app3. Android: the raw list, directly
In
RelayDirectory.kt:https://raw.githubusercontent.com/permissionlesstech/georelays/refs/heads/main/nostr_relays.csv, the upstream list, unreviewed4. Side by side
bitchatgeorelays5. Consequences for channels
5.1 The two apps don't always meet on the same relays
Each app takes the 5 closest relays from its own list. As soon as the two lists differ near a cell, the two selections differ too. A channel is then really shared only through the relays common to both selections.
Measurements from 2026-10-26 (
geohash_map, "iOS rank / Android rank" columns,-= not picked):#u09tv(Paris): 8 relays in total, only 2 shared by both apps.What this shows:
wild-vibes).#u1(Netherlands): 9 relays in total, 3 shared. The busiest relays (nostr.stakey.netwith 104 events,relay.mccormick.cxwith 123,test.relays.nuts.cashwith 98) are picked mostly, or only, by Android.5.2 Effects users see
5.3 Aggravating factors
6. What our tools do
examples/geohash_map.rsshows, for a geohash, the iOS selection and the Android selection, with each relay's rank in each and the result of a channel read test. Theoverlaymode produces a map. Relays that are down for good (certificate, DNS, connection refused, HTTP 4xx) are set aside by default;--no-drop-deadkeeps them.examples/geohash_bot.rsreads both lists (--relays-csv,--android-csv) and uses the union of both selections, to reach users of both platforms. It also sets aside relays that are down for good by default.To reproduce the measurements:
7. Suggestions (for BitChat, outside this crate)
Sources
bitchat/Nostr/GeoRelayDirectory.swift,bitchat/Services/TransportConfig.swift,.github/workflows/fetch_georelays.yml,.github/workflows/validate_georelays.yml(repositorypermissionlesstech/bitchat). History ofrelays/online_relays_gps.csv: latest commits on 2026-05-31, 06-07, 06-14, 06-21 and 07-26.app/src/main/java/com/bitchat/android/nostr/RelayDirectory.kt(repositorypermissionlesstech/bitchat-android).permissionlesstech/georelaysrepository (last updated on 2026-10-25).geohash_map, on 2026-10-26. Relay status changes from one day to the next.