Skip to content

Commit faeda9f

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

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
@@ -1634,20 +1634,22 @@ impl Client {
16341634
}
16351635

16361636
// Broken-down filters
1637-
let filters: HashMap<RelayUrl, Filter> =
1638-
match gossip.break_down_filter(filter, pattern).await? {
1639-
BrokenDownFilters::Filters(filters) => filters,
1640-
BrokenDownFilters::Orphan(filter) | BrokenDownFilters::Other(filter) => {
1641-
// Get read relays
1642-
let read_relays: Vec<RelayUrl> = self.pool.__read_relay_urls().await;
1643-
1644-
let mut map = HashMap::with_capacity(read_relays.len());
1645-
for url in read_relays.into_iter() {
1646-
map.insert(url, filter.clone());
1647-
}
1648-
map
1637+
let filters: HashMap<RelayUrl, Filter> = match gossip
1638+
.break_down_filter(filter, pattern, &self.opts.gossip)
1639+
.await?
1640+
{
1641+
BrokenDownFilters::Filters(filters) => filters,
1642+
BrokenDownFilters::Orphan(filter) | BrokenDownFilters::Other(filter) => {
1643+
// Get read relays
1644+
let read_relays: Vec<RelayUrl> = self.pool.__read_relay_urls().await;
1645+
1646+
let mut map = HashMap::with_capacity(read_relays.len());
1647+
for url in read_relays.into_iter() {
1648+
map.insert(url, filter.clone());
16491649
}
1650-
};
1650+
map
1651+
}
1652+
};
16511653

16521654
// Add gossip (outbox and inbox) relays
16531655
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?;
@@ -365,7 +396,11 @@ mod tests {
365396
// Single author
366397
let filter = Filter::new().author(keys_a.public_key);
367398
match gossip
368-
.break_down_filter(filter.clone(), GossipFilterPattern::Nip65)
399+
.break_down_filter(
400+
filter.clone(),
401+
GossipFilterPattern::Nip65,
402+
&GossipOptions::default(),
403+
)
369404
.await
370405
.unwrap()
371406
{
@@ -381,7 +416,11 @@ mod tests {
381416
// Multiple authors
382417
let authors_filter = Filter::new().authors([keys_a.public_key, keys_b.public_key]);
383418
match gossip
384-
.break_down_filter(authors_filter.clone(), GossipFilterPattern::Nip65)
419+
.break_down_filter(
420+
authors_filter.clone(),
421+
GossipFilterPattern::Nip65,
422+
&GossipOptions::default(),
423+
)
385424
.await
386425
.unwrap()
387426
{
@@ -412,7 +451,11 @@ mod tests {
412451
// Other filter
413452
let search_filter = Filter::new().search("Test").limit(10);
414453
match gossip
415-
.break_down_filter(search_filter.clone(), GossipFilterPattern::Nip65)
454+
.break_down_filter(
455+
search_filter.clone(),
456+
GossipFilterPattern::Nip65,
457+
&GossipOptions::default(),
458+
)
416459
.await
417460
.unwrap()
418461
{
@@ -425,7 +468,11 @@ mod tests {
425468
// Single p tags
426469
let p_tag_filter = Filter::new().pubkey(keys_a.public_key);
427470
match gossip
428-
.break_down_filter(p_tag_filter.clone(), GossipFilterPattern::Nip65)
471+
.break_down_filter(
472+
p_tag_filter.clone(),
473+
GossipFilterPattern::Nip65,
474+
&GossipOptions::default(),
475+
)
429476
.await
430477
.unwrap()
431478
{
@@ -446,7 +493,11 @@ mod tests {
446493
.author(keys_a.public_key)
447494
.pubkey(keys_b.public_key);
448495
match gossip
449-
.break_down_filter(filter.clone(), GossipFilterPattern::Nip65)
496+
.break_down_filter(
497+
filter.clone(),
498+
GossipFilterPattern::Nip65,
499+
&GossipOptions::default(),
500+
)
450501
.await
451502
.unwrap()
452503
{
@@ -466,7 +517,11 @@ mod tests {
466517
let random_keys = Keys::generate();
467518
let filter = Filter::new().author(random_keys.public_key);
468519
match gossip
469-
.break_down_filter(filter.clone(), GossipFilterPattern::Nip65)
520+
.break_down_filter(
521+
filter.clone(),
522+
GossipFilterPattern::Nip65,
523+
&GossipOptions::default(),
524+
)
470525
.await
471526
.unwrap()
472527
{

0 commit comments

Comments
 (0)