Skip to content

Implement NIP-91: AND operator in filters#177

Open
btcjt wants to merge 2 commits intohoytech:masterfrom
btcjt:nip-91-and-operator
Open

Implement NIP-91: AND operator in filters#177
btcjt wants to merge 2 commits intohoytech:masterfrom
btcjt:nip-91-and-operator

Conversation

@btcjt
Copy link

@btcjt btcjt commented Mar 4, 2026

Summary

  • Adds support for &-prefixed tag filters (NIP-91) that require ALL listed values to be present on an event (AND logic), complementing the existing #-prefixed OR filters
  • Example: {"&t": ["meme", "cat"], "#t": ["black", "white"]} returns events with both t=meme AND t=cat, that also have t=black OR t=white
  • AND takes precedence over OR per the spec

Changes

  • filters.h: Parse &X keys into andTags map; doesMatch() verifies all AND values present; updated isFullDbQuery, indexOnlyScans, and tag count limits
  • DBQuery.h: AND tags use 1 index cursor (scanning for any single value suffices since all must match); heuristic picks optimal tag for index scan across both OR and AND tags
  • ActiveMonitors.h: AND tag values registered in allTags inverted index for real-time subscription matching
  • RelayWebsocket.cpp: Advertise NIP-91 in NIP-11 relay info

Test plan

  • Verify compilation on Linux (Docker Alpine build)
  • Send REQ with &t filter and confirm only events with ALL specified tag values are returned
  • Send REQ with both &t and #t filters and confirm AND takes precedence over OR
  • Verify real-time subscriptions (REQ monitor) correctly match AND filters on new events — monitor: 15/15 passed
  • Run existing fuzz/test suite — scan: 30/30 passed, scan-limit: 30/30 passed

btcjt added 2 commits March 4, 2026 08:48
Add support for &-prefixed tag filters that require ALL listed values
to be present on an event (AND logic), complementing the existing
#-prefixed OR filters.

- Parse &X filter keys and store in andTags map
- doesMatch() verifies all AND tag values are present
- DBScan selects optimal index (AND tags need only 1 cursor)
- ActiveMonitors registers AND tag values for real-time matching
- Advertise NIP-91 support in NIP-11 relay info
Update dumbFilter.pl reference implementation to handle &-prefixed AND
tag filters. Add random &t filter generation to filterFuzzTest.pl so
the differential fuzzer exercises AND filter matching.

Add genTestData.pl to generate synthetic events with t-tags for testing,
and runTests.sh for running the test suite in Docker.

Verified all tests pass (Docker Alpine build):
- scan: 30/30 passed
- scan-limit: 30/30 passed
- monitor: 15/15 passed
@btcjt btcjt force-pushed the nip-91-and-operator branch from b4880fc to aaa2d6c Compare March 4, 2026 14:13
@dskvr
Copy link

dskvr commented Mar 4, 2026

Nice! #162

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants