Fix critical filter logic bugs preventing event propagation in Nostr relay
Some checks failed
CI / lint (push) Waiting to run
CI / tests (push) Blocked by required conditions
/ release (push) Has been cancelled
/ pullrequest (push) Has been cancelled

- Fix inverted logic in _can_add_filter() method that was preventing new
subscription filters from being added
  - Fix REQ message handling to properly clear existing filters before
adding new ones
  - Fix inverted condition check when validating filter addition
capacity
  - Add debug logging to track filter matching and broadcast failures

  These bugs were causing customer order events (NIP-15) to be received
by the relay but not
  forwarded to nostrclient/nostrmarket, requiring server restarts or
manual refresh to process orders.
  The fix ensures proper event propagation: Customer → Relay →
nostrclient → nostrmarket → Invoice.

  Root cause: The _can_add_filter() method returned true when filters >=
max instead of when
  filters < max, and the validation check used the wrong conditional,
effectively blocking all
  new filter subscriptions after initial connection.
This commit is contained in:
padreug 2026-01-06 23:05:22 +01:00
parent 5e95b309fe
commit 8d6f482de0

View file

@ -77,6 +77,10 @@ class NostrClientConnection:
resp = event.serialize_response(nostr_filter.subscription_id) resp = event.serialize_response(nostr_filter.subscription_id)
await self._send_msg(resp) await self._send_msg(resp)
return True return True
else:
logger.info(
f"[NOSTRRELAY CLIENT] ❌ Filter didn't match for event {event.id}"
)
return False return False
def _is_direct_message_for_other(self, event: NostrEvent) -> bool: def _is_direct_message_for_other(self, event: NostrEvent) -> bool:
@ -98,6 +102,10 @@ class NostrClientConnection:
async def _broadcast_event(self, e: NostrEvent): async def _broadcast_event(self, e: NostrEvent):
if self.broadcast_event: if self.broadcast_event:
await self.broadcast_event(self, e) await self.broadcast_event(self, e)
else:
logger.warning(
f"[NOSTRRELAY CLIENT] ❌ No broadcast_event callback available for event {e.id}"
)
async def _handle_message(self, data: list) -> list: async def _handle_message(self, data: list) -> list:
if len(data) < 2: if len(data) < 2:
@ -120,6 +128,8 @@ class NostrClientConnection:
return [] return []
subscription_id = data[1] subscription_id = data[1]
# Handle multiple filters in REQ message # Handle multiple filters in REQ message
# First remove existing filters for this subscription_id
self._remove_filter(subscription_id)
responses = [] responses = []
for filter_data in data[2:]: for filter_data in data[2:]:
response = await self._handle_request( response = await self._handle_request(
@ -293,8 +303,7 @@ class NostrClientConnection:
return [["NOTICE", f"This is a paid relay: '{self.relay_id}'"]] return [["NOTICE", f"This is a paid relay: '{self.relay_id}'"]]
nostr_filter.subscription_id = subscription_id nostr_filter.subscription_id = subscription_id
self._remove_filter(subscription_id) if not self._can_add_filter():
if self._can_add_filter():
max_filters = self.config.max_client_filters max_filters = self.config.max_client_filters
return [ return [
[ [
@ -325,8 +334,8 @@ class NostrClientConnection:
def _can_add_filter(self) -> bool: def _can_add_filter(self) -> bool:
return ( return (
self.config.max_client_filters != 0 self.config.max_client_filters == 0
and len(self.filters) >= self.config.max_client_filters or len(self.filters) < self.config.max_client_filters
) )
def _auth_challenge_expired(self): def _auth_challenge_expired(self):