upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/nostr.cpp
diff options
context:
space:
mode:
authorBitflash <btf01@proton.me>2026-07-31 09:30:41 -0300
committerGitHub <noreply@github.com>2026-07-31 09:30:41 -0300
commitf2ea483df4b2277abe13cc19bcc0bc5834c2e3e6 (patch)
tree6a96f30576fcd6fa18246f3a2ee7492f4d4d4cd0 /src/nostr.cpp
parent7243bbead29d68c9f8ae9a022669b02179e352e2 (diff)
nostr: back off from a relay that is down, and replace one that is (#64)
relay.nostr.band went down and stayed down -- it resolves and refuses TCP on 443, from several networks. The seed accumulated 1092 identical error lines about it. The log noise was the small half. The discovery loop walks every relay in turn with a ten-second connect timeout, so a dead relay added ten seconds to every pass, forever, and that loop is what finds peers -- a relay that answers nobody was slowing down the ones that answer everybody. Back off per relay: 30s after the first failure, doubling to a fifteen minute ceiling, cleared the moment it answers again. Only when an attempt happens changes; nothing about whether discovery is correct. Also swapped relay.nostr.band for nostr.bitcoiner.social, on 206.245.132.32 -- neither Cloudflare nor Hetzner, which is the diversity rule the list already follows. Verified with a deliberately bogus relay in the list: backoff stepped 30s -> 60s -> 120s and the dead entry produced nine lines in four minutes instead of one per pass, while the node still connected to five relays, discovered 54 fresh peers and followed the chain.
Diffstat (limited to 'src/nostr.cpp')
-rw-r--r--src/nostr.cpp81
1 files changed, 79 insertions, 2 deletions
diff --git a/src/nostr.cpp b/src/nostr.cpp
index 088174a..17139ad 100644
--- a/src/nostr.cpp
+++ b/src/nostr.cpp
@@ -83,7 +83,11 @@ static CCriticalSection cs_btfPeers;
83const char* pszNostrRelays[] = { 83const char* pszNostrRelays[] = {
84 "wss://relay.damus.io", 84 "wss://relay.damus.io",
85 "wss://nos.lol", 85 "wss://nos.lol",
86 "wss://relay.nostr.band", 86 // Was relay.nostr.band, which went down and stayed down (2026-07-31:
87 // resolves, refuses TCP on 443, from several networks). Replaced with a
88 // relay on a different upstream again -- 206.245.132.32, neither
89 // Cloudflare nor Hetzner, which the rest of this list already leans on.
90 "wss://nostr.bitcoiner.social",
87 "wss://nostr21.com", 91 "wss://nostr21.com",
88 "wss://offchain.pub", 92 "wss://offchain.pub",
89 "wss://nostr.mom", 93 "wss://nostr.mom",
@@ -1172,6 +1176,74 @@ bool BtfResolveMany(const std::vector<std::string>& btfAddrs,
1172} 1176}
1173 1177
1174 1178
1179// ---- per-relay backoff -----------------------------------------------------
1180//
1181// A relay that is down costs the whole discovery loop the full connect timeout,
1182// every round, forever. relay.nostr.band went down and produced 1092 identical
1183// error lines on the seed while adding ten seconds to every pass -- and the
1184// loop is what discovers peers, so a dead relay was slowing down the live ones.
1185//
1186// Back off per relay instead: 30s after the first failure, doubling to a
1187// fifteen-minute ceiling, cleared the moment it answers again. This changes
1188// only when an attempt happens, never whether discovery is correct.
1189struct CRelayBackoff
1190{
1191 int64 nNextTry;
1192 int nFails;
1193 CRelayBackoff() : nNextTry(0), nFails(0) {}
1194};
1195static map<string, CRelayBackoff> mapRelayBackoff;
1196static CCriticalSection cs_relayBackoff;
1197
1198static const int64 RELAY_BACKOFF_BASE_SECS = 30;
1199static const int64 RELAY_BACKOFF_MAX_SECS = 15 * 60;
1200
1201static bool RelayDueForRetry(const string& relay)
1202{
1203 CRITICAL_BLOCK(cs_relayBackoff)
1204 {
1205 map<string, CRelayBackoff>::iterator it = mapRelayBackoff.find(relay);
1206 if (it == mapRelayBackoff.end())
1207 return true;
1208 return GetTime() >= it->second.nNextTry;
1209 }
1210 return true;
1211}
1212
1213static void RelayNoteFailure(const string& relay)
1214{
1215 CRITICAL_BLOCK(cs_relayBackoff)
1216 {
1217 CRelayBackoff& b = mapRelayBackoff[relay];
1218 b.nFails++;
1219 int64 nWait = RELAY_BACKOFF_BASE_SECS;
1220 for (int i = 1; i < b.nFails && nWait < RELAY_BACKOFF_MAX_SECS; i++)
1221 nWait *= 2;
1222 if (nWait > RELAY_BACKOFF_MAX_SECS)
1223 nWait = RELAY_BACKOFF_MAX_SECS;
1224 b.nNextTry = GetTime() + nWait;
1225 // Only on the way in, so a relay that stays down says this once per
1226 // backoff step rather than once per pass.
1227 LogPrint("nostr", "Nostr: %s unreachable (%d in a row), not retrying for %ds\n",
1228 relay.c_str(), b.nFails, (int)nWait);
1229 }
1230}
1231
1232static void RelayNoteSuccess(const string& relay)
1233{
1234 CRITICAL_BLOCK(cs_relayBackoff)
1235 {
1236 map<string, CRelayBackoff>::iterator it = mapRelayBackoff.find(relay);
1237 if (it != mapRelayBackoff.end())
1238 {
1239 if (it->second.nFails > 0)
1240 LogPrint("nostr", "Nostr: %s answering again after %d failure(s)\n",
1241 relay.c_str(), it->second.nFails);
1242 mapRelayBackoff.erase(it);
1243 }
1244 }
1245}
1246
1175// Connect to a relay: publish our .btf descriptor and collect relay data. 1247// Connect to a relay: publish our .btf descriptor and collect relay data.
1176static bool SeedFromRelay(CNostrKey& key, const string& relay) 1248static bool SeedFromRelay(CNostrKey& key, const string& relay)
1177{ 1249{
@@ -1653,9 +1725,14 @@ void ThreadNostrSeed(void* parg)
1653 for (int i = 0; i < nNostrRelays; i++) 1725 for (int i = 0; i < nNostrRelays; i++)
1654 { 1726 {
1655 if (fShutdown) return; 1727 if (fShutdown) return;
1728 if (!RelayDueForRetry(pszNostrRelays[i]))
1729 continue;
1656 try 1730 try
1657 { 1731 {
1658 SeedFromRelay(key, pszNostrRelays[i]); 1732 if (SeedFromRelay(key, pszNostrRelays[i]))
1733 RelayNoteSuccess(pszNostrRelays[i]);
1734 else
1735 RelayNoteFailure(pszNostrRelays[i]);
1659 } 1736 }
1660 CATCH_PRINT_EXCEPTION("SeedFromRelay") 1737 CATCH_PRINT_EXCEPTION("SeedFromRelay")
1661 } 1738 }