Avoid note subscription clipping in HomeModel

This commit adds a new event subscription task in HomeModel, one which
streams low volume but important filters from NostrDB.

This was done to address an issue where the contact filters in the
general handler task could yield too many notes from NostrDB, hitting
its limits and clipping off important events such as mute-lists, leading
to downstream issues such as unintended mute-list overrides.

This issue was not present since the last public release, therefore no
changelog entry is needed.

Changelog-None
Closes: https://github.com/damus-io/damus/issues/3256
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit is contained in:
Daniel D’Aquino
2025-10-31 16:23:44 -07:00
parent bd1eae5f26
commit 58f4988237
2 changed files with 17 additions and 4 deletions

View File

@@ -533,7 +533,7 @@ extension NostrNetworkManager {
/// Returns notes from both NostrDB and the network, in parallel, treating it with similar importance against the network relays. Generic EOSE is fired when EOSE is received from both the network and NostrDB /// Returns notes from both NostrDB and the network, in parallel, treating it with similar importance against the network relays. Generic EOSE is fired when EOSE is received from both the network and NostrDB
/// `optimizeNetworkFilter`: Returns notes from ndb, then streams from the network with an added "since" filter set to the latest note stored on ndb. /// `optimizeNetworkFilter`: Returns notes from ndb, then streams from the network with an added "since" filter set to the latest note stored on ndb.
case ndbAndNetworkParallel(optimizeNetworkFilter: Bool) case ndbAndNetworkParallel(optimizeNetworkFilter: Bool)
/// Ignores the network. Used for testing purposes /// Ignores the network.
case ndbOnly case ndbOnly
var optimizeNetworkFilter: Bool { var optimizeNetworkFilter: Bool {

View File

@@ -68,6 +68,7 @@ class HomeModel: ContactsDelegate, ObservableObject {
var homeHandlerTask: Task<Void, Never>? var homeHandlerTask: Task<Void, Never>?
var notificationsHandlerTask: Task<Void, Never>? var notificationsHandlerTask: Task<Void, Never>?
var generalHandlerTask: Task<Void, Never>? var generalHandlerTask: Task<Void, Never>?
var ndbOnlyHandlerTask: Task<Void, Never>?
var nwcHandlerTask: Task<Void, Never>? var nwcHandlerTask: Task<Void, Never>?
@Published var loading: Bool = true @Published var loading: Bool = true
@@ -512,10 +513,11 @@ class HomeModel: ContactsDelegate, ObservableObject {
notifications_filter.pubkeys = [damus_state.pubkey] notifications_filter.pubkeys = [damus_state.pubkey]
notifications_filter.limit = 500 notifications_filter.limit = 500
var notifications_filters = [notifications_filter] let notifications_filters = [notifications_filter]
let contacts_filter_chunks = contacts_filter.chunked(on: .authors, into: MAX_CONTACTS_ON_FILTER) let contacts_filter_chunks = contacts_filter.chunked(on: .authors, into: MAX_CONTACTS_ON_FILTER)
var contacts_filters = contacts_filter_chunks + [our_contacts_filter, our_blocklist_filter, our_old_blocklist_filter, contact_cards_filter] let low_volume_important_filters = [our_contacts_filter, our_blocklist_filter, our_old_blocklist_filter, contact_cards_filter]
var dms_filters = [dms_filter, our_dms_filter] let contacts_filters = contacts_filter_chunks + low_volume_important_filters
let dms_filters = [dms_filter, our_dms_filter]
//print_filters(relay_id: relay_id, filters: [home_filters, contacts_filters, notifications_filters, dms_filters]) //print_filters(relay_id: relay_id, filters: [home_filters, contacts_filters, notifications_filters, dms_filters])
@@ -543,6 +545,17 @@ class HomeModel: ContactsDelegate, ObservableObject {
} }
} }
} }
// Due to subscription volume limits in ndb and in relays, some important events may get clipped in the `generalHandlerTask` above.
// This could lead to issues (e.g. The app overriding a mutelist because it does not have it)
// Therefore, we have this ndb-only stream for some low volume important items.
// The reason we do not separate into two complete streams is because
// we need to keep total relay subscription down to avoid relay subscription limits.
self.ndbOnlyHandlerTask?.cancel()
self.ndbOnlyHandlerTask = Task {
for await eventLender in damus_state.nostrNetwork.reader.streamIndefinitely(filters: low_volume_important_filters, streamMode: .ndbOnly) {
await eventLender.justUseACopy({ await process_event(ev: $0, context: .other) })
}
}
self.nwcHandlerTask?.cancel() self.nwcHandlerTask?.cancel()
self.nwcHandlerTask = Task { self.nwcHandlerTask = Task {
if let nwc_str = damus_state.settings.nostr_wallet_connect, if let nwc_str = damus_state.settings.nostr_wallet_connect,