upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/nostr/builder.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-02-18 19:41:29 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-02-18 19:41:29 +0000
commite22021f0b248ebcf3bd09210d59b2cdb4701032f (patch)
tree3dd1a3a75a8b7424749c0b0505a3d1ab61ac7895 /src/nostr/builder.rs
parenta804164468d3beafb243ece12555b4d1692a075d (diff)
fix: simplify purgatory sync - fix SelfSubscriber sync_level upgrade and negentropy fallback
Three targeted fixes for purgatory announcement sync: 1. SelfSubscriber sync_level upgrade: After or_insert_with in process_batch, always set entry.sync_level = SyncLevel::Full so that when a promoted announcement is broadcast via notify_event and SelfSubscriber receives it, an existing StateOnly entry gets upgraded to Full and PR event subscriptions are triggered immediately (not delayed up to 24h). 2. Negentropy fallback filter split: In handle_eose, when falling back from negentropy to REQ+EOSE, split batch_repos by SyncLevel and call build_sync_level_aware_filters instead of build_layer2_and_layer3_filters. Prevents StateOnly (purgatory) repos from getting Layer 2 #a/#A/#q filters prematurely, which caused nostr-sdk client deduplication to permanently drop PR events after orphan rejection. 3. Recompute sync filters after announcement batch EOSE: Add recompute_new_sync_filters_for_relay calls at all three batch-completion paths in handle_eose for generic filter (announcement) batches. This triggers state-only subscriptions for any purgatory repos registered during that batch, fixing the 24h delay before state event sync starts. 4. User-submitted purgatory announcements: Add repo_sync_index field to PolicyContext with setter/getter, wire in main.rs after SyncManager creation, and register in AcceptPurgatory handler so user-submitted announcements get StateOnly sync started immediately. 5. Update archive tests: test_archive_without_state_events_does_not_sync_git updated to reflect that StateOnly subscription now proactively fetches state events from source relays. test_archive_read_only_creates_bare_repo un-ignored as it now works end-to-end.
Diffstat (limited to 'src/nostr/builder.rs')
-rw-r--r--src/nostr/builder.rs54
1 files changed, 54 insertions, 0 deletions
diff --git a/src/nostr/builder.rs b/src/nostr/builder.rs
index aff12a6..8d1e461 100644
--- a/src/nostr/builder.rs
+++ b/src/nostr/builder.rs
@@ -17,6 +17,7 @@ use crate::nostr::policy::{
17 AnnouncementPolicy, AnnouncementResult, PolicyContext, PrEventPolicy, ReferenceResult, 17 AnnouncementPolicy, AnnouncementResult, PolicyContext, PrEventPolicy, ReferenceResult,
18 RelatedEventPolicy, StatePolicy, StateResult, 18 RelatedEventPolicy, StatePolicy, StateResult,
19}; 19};
20use crate::sync::{RepoSyncIndex, RepoSyncNeeds, SyncLevel};
20 21
21/// Type alias for the shared database used by the relay 22/// Type alias for the shared database used by the relay
22pub type SharedDatabase = Arc<dyn NostrDatabase>; 23pub type SharedDatabase = Arc<dyn NostrDatabase>;
@@ -98,6 +99,14 @@ impl Nip34WritePolicy {
98 self.ctx.set_local_relay(relay); 99 self.ctx.set_local_relay(relay);
99 } 100 }
100 101
102 /// Set the repo sync index so that user-submitted purgatory announcements can
103 /// be registered for state event sync immediately.
104 ///
105 /// This must be called after SyncManager is created.
106 pub fn set_repo_sync_index(&self, index: RepoSyncIndex) {
107 self.ctx.set_repo_sync_index(index);
108 }
109
101 /// Handle repository announcement event 110 /// Handle repository announcement event
102 async fn handle_announcement(&self, event: &Event) -> WritePolicyResult { 111 async fn handle_announcement(&self, event: &Event) -> WritePolicyResult {
103 let event_id_str = event.id.to_bech32().unwrap_or_else(|_| event.id.to_hex()); 112 let event_id_str = event.id.to_bech32().unwrap_or_else(|_| event.id.to_hex());
@@ -146,6 +155,51 @@ impl Nip34WritePolicy {
146 "Accepted announcement to purgatory: {} (waiting for git data)", 155 "Accepted announcement to purgatory: {} (waiting for git data)",
147 event_id_str 156 event_id_str
148 ); 157 );
158
159 // Register repo in repo_sync_index with StateOnly level so that
160 // state event sync starts promptly via the next batch EOSE recompute.
161 // This handles user-submitted purgatory announcements - the SelfSubscriber
162 // only sees DB events, so it won't pick these up automatically.
163 if let Some(repo_sync_index) = self.ctx.get_repo_sync_index() {
164 if let Ok(announcement) =
165 RepositoryAnnouncement::from_event(event.clone())
166 {
167 use std::collections::HashSet;
168 let repo_id = format!(
169 "30617:{}:{}",
170 event.pubkey,
171 announcement.identifier
172 );
173
174 // Extract relay URLs from the announcement event tags
175 let relays: HashSet<String> = event
176 .tags
177 .iter()
178 .flat_map(|tag| {
179 let tag_vec = tag.as_slice();
180 if !tag_vec.is_empty() && tag_vec[0] == "relays" {
181 tag_vec[1..].iter().map(|s| s.to_string()).collect::<Vec<_>>()
182 } else {
183 vec![]
184 }
185 })
186 .collect();
187
188 let mut index = repo_sync_index.write().await;
189 index.entry(repo_id.clone()).or_insert_with(|| RepoSyncNeeds {
190 relays,
191 root_events: HashSet::new(),
192 sync_level: SyncLevel::StateOnly,
193 });
194 drop(index);
195
196 tracing::debug!(
197 repo_id = %repo_id,
198 "Registered purgatory announcement in repo_sync_index as StateOnly"
199 );
200 }
201 }
202
149 WritePolicyResult::Reject { 203 WritePolicyResult::Reject {
150 status: true, // Client sees OK 204 status: true, // Client sees OK
151 message: "purgatory: won't be served until git data arrives".into(), 205 message: "purgatory: won't be served until git data arrives".into(),