Skip to content

Commit dcffe83

Browse files
committed
sdk: add configurable gossip relay limits
Signed-off-by: Yuki Kishimoto <[email protected]>
1 parent 5603d71 commit dcffe83

File tree

3 files changed

+125
-39
lines changed

3 files changed

+125
-39
lines changed

crates/nostr-sdk/src/client/mod.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,20 +1481,22 @@ impl Client {
14811481
}
14821482

14831483
// Broken-down filters
1484-
let filters: HashMap<RelayUrl, Filter> =
1485-
match gossip.break_down_filter(filter, pattern).await? {
1486-
BrokenDownFilters::Filters(filters) => filters,
1487-
BrokenDownFilters::Orphan(filter) | BrokenDownFilters::Other(filter) => {
1488-
// Get read relays
1489-
let read_relays: Vec<RelayUrl> = self.pool.__read_relay_urls().await;
1490-
1491-
let mut map = HashMap::with_capacity(read_relays.len());
1492-
for url in read_relays.into_iter() {
1493-
map.insert(url, filter.clone());
1494-
}
1495-
map
1484+
let filters: HashMap<RelayUrl, Filter> = match gossip
1485+
.break_down_filter(filter, pattern, &self.opts.gossip)
1486+
.await?
1487+
{
1488+
BrokenDownFilters::Filters(filters) => filters,
1489+
BrokenDownFilters::Orphan(filter) | BrokenDownFilters::Other(filter) => {
1490+
// Get read relays
1491+
let read_relays: Vec<RelayUrl> = self.pool.__read_relay_urls().await;
1492+
1493+
let mut map = HashMap::with_capacity(read_relays.len());
1494+
for url in read_relays.into_iter() {
1495+
map.insert(url, filter.clone());
14961496
}
1497-
};
1497+
map
1498+
}
1499+
};
14981500

14991501
// Add gossip (outbox and inbox) relays
15001502
for url in filters.keys() {

crates/nostr-sdk/src/client/options.rs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,33 @@ use std::time::Duration;
1212

1313
use nostr_relay_pool::prelude::*;
1414

15+
/// Gossip options
16+
#[derive(Debug, Clone, Copy)]
17+
pub struct GossipOptions {
18+
/// Max number of **read** relays per user
19+
pub read_relays_per_user: usize,
20+
/// Max number of **write** relays per user
21+
pub write_relays_per_user: usize,
22+
/// Max number of **hint** relays per user
23+
pub hint_relays_per_user: usize,
24+
/// Max number of **most used** relays per user
25+
pub most_used_relays_per_user: usize,
26+
/// Max number of NIP-17 relays per user
27+
pub nip17_relays: usize,
28+
}
29+
30+
impl Default for GossipOptions {
31+
fn default() -> Self {
32+
Self {
33+
read_relays_per_user: 3,
34+
write_relays_per_user: 3,
35+
hint_relays_per_user: 1,
36+
most_used_relays_per_user: 1,
37+
nip17_relays: 3,
38+
}
39+
}
40+
}
41+
1542
/// Options
1643
#[derive(Debug, Clone, Default)]
1744
pub struct ClientOptions {
@@ -24,6 +51,7 @@ pub struct ClientOptions {
2451
pub(super) verify_subscriptions: bool,
2552
pub(super) ban_relay_on_mismatch: bool,
2653
pub(super) pool: RelayPoolOptions,
54+
pub(super) gossip: GossipOptions,
2755
}
2856

2957
impl ClientOptions {
@@ -51,12 +79,6 @@ impl ClientOptions {
5179
self
5280
}
5381

54-
/// Enable gossip model (default: false)
55-
#[deprecated(since = "0.44.0", note = "Use ClientBuilder::gossip instead")]
56-
pub fn gossip(self, _enable: bool) -> Self {
57-
self
58-
}
59-
6082
/// Connection mode and target
6183
#[inline]
6284
#[cfg(not(target_arch = "wasm32"))]
@@ -100,6 +122,13 @@ impl ClientOptions {
100122
self
101123
}
102124

125+
/// Set gossip options
126+
#[inline]
127+
pub fn gossip(mut self, opts: GossipOptions) -> Self {
128+
self.gossip = opts;
129+
self
130+
}
131+
103132
/// Set relay pool options
104133
#[inline]
105134
pub fn pool(mut self, opts: RelayPoolOptions) -> Self {

crates/nostr-sdk/src/gossip/mod.rs

Lines changed: 75 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ use std::sync::Arc;
99
use nostr::prelude::*;
1010
use nostr_gossip::{BestRelaySelection, NostrGossip};
1111

12+
use crate::client::options::GossipOptions;
1213
use crate::client::Error;
1314

1415
const P_TAG: SingleLetterTag = SingleLetterTag::lowercase(Alphabet::P);
15-
const MAX_NIP17_RELAYS: usize = 3;
1616

1717
#[derive(Debug)]
1818
pub enum BrokenDownFilters {
@@ -94,6 +94,7 @@ impl GossipWrapper {
9494
&self,
9595
filter: Filter,
9696
pattern: GossipFilterPattern,
97+
opts: &GossipOptions,
9798
) -> Result<BrokenDownFilters, Error> {
9899
// Extract `p` tag from generic tags and parse public key hex
99100
let p_tag: Option<BTreeSet<PublicKey>> = filter.generic_tags.get(&P_TAG).map(|s| {
@@ -107,17 +108,32 @@ impl GossipWrapper {
107108
(Some(authors), None) => {
108109
// Get map of write relays
109110
let mut outbox: HashMap<RelayUrl, BTreeSet<PublicKey>> = self
110-
.map_relays(authors, BestRelaySelection::Write { limit: 2 })
111+
.map_relays(
112+
authors,
113+
BestRelaySelection::Write {
114+
limit: opts.write_relays_per_user,
115+
},
116+
)
111117
.await?;
112118

113119
// Get map of hints relays
114120
let hints: HashMap<RelayUrl, BTreeSet<PublicKey>> = self
115-
.map_relays(authors, BestRelaySelection::Hints { limit: 1 })
121+
.map_relays(
122+
authors,
123+
BestRelaySelection::Hints {
124+
limit: opts.hint_relays_per_user,
125+
},
126+
)
116127
.await?;
117128

118129
// Get map of relays that received more events
119130
let most_received: HashMap<RelayUrl, BTreeSet<PublicKey>> = self
120-
.map_relays(authors, BestRelaySelection::MostReceived { limit: 1 })
131+
.map_relays(
132+
authors,
133+
BestRelaySelection::MostReceived {
134+
limit: opts.most_used_relays_per_user,
135+
},
136+
)
121137
.await?;
122138

123139
// Extend with hints and most received
@@ -130,7 +146,7 @@ impl GossipWrapper {
130146
.map_relays(
131147
authors,
132148
BestRelaySelection::PrivateMessage {
133-
limit: MAX_NIP17_RELAYS,
149+
limit: opts.nip17_relays,
134150
},
135151
)
136152
.await?;
@@ -160,17 +176,32 @@ impl GossipWrapper {
160176
(None, Some(p_public_keys)) => {
161177
// Get map of inbox relays
162178
let mut inbox: HashMap<RelayUrl, BTreeSet<PublicKey>> = self
163-
.map_relays(p_public_keys, BestRelaySelection::Read { limit: 2 })
179+
.map_relays(
180+
p_public_keys,
181+
BestRelaySelection::Read {
182+
limit: opts.read_relays_per_user,
183+
},
184+
)
164185
.await?;
165186

166187
// Get map of hints relays
167188
let hints: HashMap<RelayUrl, BTreeSet<PublicKey>> = self
168-
.map_relays(p_public_keys, BestRelaySelection::Hints { limit: 1 })
189+
.map_relays(
190+
p_public_keys,
191+
BestRelaySelection::Hints {
192+
limit: opts.hint_relays_per_user,
193+
},
194+
)
169195
.await?;
170196

171197
// Get map of relays that received more events
172198
let most_received: HashMap<RelayUrl, BTreeSet<PublicKey>> = self
173-
.map_relays(p_public_keys, BestRelaySelection::MostReceived { limit: 1 })
199+
.map_relays(
200+
p_public_keys,
201+
BestRelaySelection::MostReceived {
202+
limit: opts.most_used_relays_per_user,
203+
},
204+
)
174205
.await?;
175206

176207
// Extend with hints and most received
@@ -184,7 +215,7 @@ impl GossipWrapper {
184215
.map_relays(
185216
p_public_keys,
186217
BestRelaySelection::PrivateMessage {
187-
limit: MAX_NIP17_RELAYS,
218+
limit: opts.nip17_relays,
188219
},
189220
)
190221
.await?;
@@ -221,10 +252,10 @@ impl GossipWrapper {
221252
.get_relays(
222253
union.iter(),
223254
BestRelaySelection::All {
224-
read: 2,
225-
write: 2,
226-
hints: 1,
227-
most_received: 1,
255+
read: opts.read_relays_per_user,
256+
write: opts.write_relays_per_user,
257+
hints: opts.hint_relays_per_user,
258+
most_received: opts.most_used_relays_per_user,
228259
},
229260
)
230261
.await?;
@@ -236,7 +267,7 @@ impl GossipWrapper {
236267
.get_relays(
237268
union.iter(),
238269
BestRelaySelection::PrivateMessage {
239-
limit: MAX_NIP17_RELAYS,
270+
limit: opts.nip17_relays,
240271
},
241272
)
242273
.await?;
@@ -369,7 +400,11 @@ mod tests {
369400
// Single author
370401
let filter = Filter::new().author(keys_a.public_key);
371402
match gossip
372-
.break_down_filter(filter.clone(), GossipFilterPattern::Nip65)
403+
.break_down_filter(
404+
filter.clone(),
405+
GossipFilterPattern::Nip65,
406+
&GossipOptions::default(),
407+
)
373408
.await
374409
.unwrap()
375410
{
@@ -385,7 +420,11 @@ mod tests {
385420
// Multiple authors
386421
let authors_filter = Filter::new().authors([keys_a.public_key, keys_b.public_key]);
387422
match gossip
388-
.break_down_filter(authors_filter.clone(), GossipFilterPattern::Nip65)
423+
.break_down_filter(
424+
authors_filter.clone(),
425+
GossipFilterPattern::Nip65,
426+
&GossipOptions::default(),
427+
)
389428
.await
390429
.unwrap()
391430
{
@@ -416,7 +455,11 @@ mod tests {
416455
// Other filter
417456
let search_filter = Filter::new().search("Test").limit(10);
418457
match gossip
419-
.break_down_filter(search_filter.clone(), GossipFilterPattern::Nip65)
458+
.break_down_filter(
459+
search_filter.clone(),
460+
GossipFilterPattern::Nip65,
461+
&GossipOptions::default(),
462+
)
420463
.await
421464
.unwrap()
422465
{
@@ -429,7 +472,11 @@ mod tests {
429472
// Single p tags
430473
let p_tag_filter = Filter::new().pubkey(keys_a.public_key);
431474
match gossip
432-
.break_down_filter(p_tag_filter.clone(), GossipFilterPattern::Nip65)
475+
.break_down_filter(
476+
p_tag_filter.clone(),
477+
GossipFilterPattern::Nip65,
478+
&GossipOptions::default(),
479+
)
433480
.await
434481
.unwrap()
435482
{
@@ -450,7 +497,11 @@ mod tests {
450497
.author(keys_a.public_key)
451498
.pubkey(keys_b.public_key);
452499
match gossip
453-
.break_down_filter(filter.clone(), GossipFilterPattern::Nip65)
500+
.break_down_filter(
501+
filter.clone(),
502+
GossipFilterPattern::Nip65,
503+
&GossipOptions::default(),
504+
)
454505
.await
455506
.unwrap()
456507
{
@@ -470,7 +521,11 @@ mod tests {
470521
let random_keys = Keys::generate();
471522
let filter = Filter::new().author(random_keys.public_key);
472523
match gossip
473-
.break_down_filter(filter.clone(), GossipFilterPattern::Nip65)
524+
.break_down_filter(
525+
filter.clone(),
526+
GossipFilterPattern::Nip65,
527+
&GossipOptions::default(),
528+
)
474529
.await
475530
.unwrap()
476531
{

0 commit comments

Comments
 (0)