Split out of the review on #712, where it was found while verifying that PR's shouldReconnectToRelayOnNotice: false change.
Problem
shouldReconnectToRelayOnNotice is a dead parameter in the pinned dart_nostr fork (anasfik/nostr ref ca07ddd, pubspec.yaml:37-40). It is threaded through a dozen function signatures and never read in any condition — no if (shouldReconnectToRelayOnNotice) exists anywhere in the library. _handleNoticeFromRelay (lib/nostr/instance/relays/relays.dart:1048-1094) closes and reconnects unconditionally:
if (nostrRegistry.isRelayRegistered(relay)) {
registeredRelay?.sink.close().then((value) {
final relayUnregistered = nostrRegistry.unregisterRelay(relay);
_reconnectToRelay(relayUnregistered: relayUnregistered, relay: relay, ...);
});
}
_reconnectToRelay has no backoff, so a relay that greets every connection with a NOTICE puts the app in a tight reconnect loop.
Impact
Roughly 127 WebSocket handshakes per second against a single relay, with no throttling at all. The trigger is any relay that sends a NOTICE on every connection — which is what relays doing auth-required or persistent rate-limiting do. Not the common case, but when it happens the app burns far more than the periodic recovery work #712 targets, and it happens on main today.
Reproduction
Point dart_nostr directly (no app) at a local relay on ws://127.0.0.1:7788 that answers every connection with ["NOTICE","rate-limited: slow down"], with both socket-level retries off, so any reconnection can only come from the notice handler:
shouldReconnectToRelayOnNotice: false,
retryOnClose: false,
retryOnError: false,
Connections the server accepts in ~10 seconds:
| flag |
connections |
false |
1273 |
true |
1926 |
Same order of magnitude either way — the difference is machine load, not the flag. The behavior is identical with the flag on or off, which is what confirms it is dead.
Fix
Belongs in the fork: either honor the flag in _handleNoticeFromRelay, or at minimum add backoff to _reconnectToRelay.
Split out of the review on #712, where it was found while verifying that PR's
shouldReconnectToRelayOnNotice: falsechange.Problem
shouldReconnectToRelayOnNoticeis a dead parameter in the pinneddart_nostrfork (anasfik/nostrrefca07ddd,pubspec.yaml:37-40). It is threaded through a dozen function signatures and never read in any condition — noif (shouldReconnectToRelayOnNotice)exists anywhere in the library._handleNoticeFromRelay(lib/nostr/instance/relays/relays.dart:1048-1094) closes and reconnects unconditionally:_reconnectToRelayhas no backoff, so a relay that greets every connection with a NOTICE puts the app in a tight reconnect loop.Impact
Roughly 127 WebSocket handshakes per second against a single relay, with no throttling at all. The trigger is any relay that sends a NOTICE on every connection — which is what relays doing
auth-requiredor persistent rate-limiting do. Not the common case, but when it happens the app burns far more than the periodic recovery work #712 targets, and it happens onmaintoday.Reproduction
Point
dart_nostrdirectly (no app) at a local relay onws://127.0.0.1:7788that answers every connection with["NOTICE","rate-limited: slow down"], with both socket-level retries off, so any reconnection can only come from the notice handler:Connections the server accepts in ~10 seconds:
falsetrueSame order of magnitude either way — the difference is machine load, not the flag. The behavior is identical with the flag on or off, which is what confirms it is dead.
Fix
Belongs in the fork: either honor the flag in
_handleNoticeFromRelay, or at minimum add backoff to_reconnectToRelay.