Skip to content

Commit 8c03d6d

Browse files
committed
relay-pool: add RelayOptions::verify_subscriptions option
Follow-up of 71b4fd7 Pull-Request: #997 Signed-off-by: Yuki Kishimoto <[email protected]>
1 parent 906deb6 commit 8c03d6d

File tree

4 files changed

+50
-17
lines changed

4 files changed

+50
-17
lines changed

crates/nostr-relay-pool/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
- Allow putting relays to sleep when idle (https://github.com/rust-nostr/nostr/pull/926)
4444
- An option to ban relays that send events which don't match the subscription filter (https://github.com/rust-nostr/nostr/pull/981)
45+
- Add `RelayOptions::verify_subscriptions` option (https://github.com/rust-nostr/nostr/pull/997)
4546

4647
## v0.42.0 - 2025/05/20
4748

crates/nostr-relay-pool/src/relay/inner.rs

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,22 +1116,36 @@ impl InnerRelay {
11161116
}
11171117
}
11181118

1119-
// Check if the subscription id exist and verify if the event matches the subscription filter.
1120-
match self.subscription(&subscription_id).await {
1121-
Some(filter) => {
1122-
// Skip NIP-50 extensions since they're unsupported
1123-
const MATCH_EVENT_OPTS: MatchEventOptions = MatchEventOptions::new().nip50(false);
1124-
1125-
// If the "ban relay on mismatch" option is enabled, check if the filter matches the event.
1126-
if self.opts.ban_relay_on_mismatch && !filter.match_event(&event, MATCH_EVENT_OPTS)
1127-
{
1128-
// Filter doesn't match the event, ban the relay.
1129-
self.ban();
1130-
return Err(Error::FilterMismatch);
1119+
// Check if subscription must be verified
1120+
if self.opts.verify_subscriptions {
1121+
// NOTE: here we don't use the `self.subscription(id)` to avoid an unnecessary clone of the filter!
1122+
1123+
// Acquire read lock
1124+
let subscriptions = self.atomic.subscriptions.read().await;
1125+
1126+
// Check if the subscription id exist and verify if the event matches the subscription filter.
1127+
match subscriptions.get(&subscription_id) {
1128+
Some(SubscriptionData { filter, .. }) => {
1129+
// Skip NIP-50 matches since they may create issues and ban non-malicious relays.
1130+
const MATCH_EVENT_OPTS: MatchEventOptions =
1131+
MatchEventOptions::new().nip50(false);
1132+
1133+
// Check if the filter matches the event
1134+
if !filter.match_event(&event, MATCH_EVENT_OPTS) {
1135+
// Ban the relay
1136+
if self.opts.ban_relay_on_mismatch {
1137+
self.ban();
1138+
}
1139+
1140+
return Err(Error::FilterMismatch);
1141+
}
1142+
1143+
// TODO: check filter limit: if eose is not received and the filter has a limit, check how many events have been received.
1144+
// TODO: use atomics (AtomicBool and AtomicUsize) for this, to avoid acquiring the RwLock as write.
1145+
}
1146+
None => {
1147+
return Err(Error::SubscriptionNotFound);
11311148
}
1132-
}
1133-
None => {
1134-
return Err(Error::SubscriptionNotFound);
11351149
}
11361150
}
11371151

crates/nostr-relay-pool/src/relay/mod.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,7 +1183,12 @@ mod tests {
11831183
let mock = MockRelay::run_with_opts(opts).await.unwrap();
11841184
let url = RelayUrl::parse(&mock.url()).unwrap();
11851185

1186-
let relay: Relay = new_relay(url, RelayOptions::default().ban_relay_on_mismatch(true));
1186+
let relay: Relay = new_relay(
1187+
url,
1188+
RelayOptions::default()
1189+
.verify_subscriptions(true)
1190+
.ban_relay_on_mismatch(true),
1191+
);
11871192

11881193
assert_eq!(relay.status(), RelayStatus::Initialized);
11891194

@@ -1212,7 +1217,12 @@ mod tests {
12121217
let mock = MockRelay::run_with_opts(opts).await.unwrap();
12131218
let url = RelayUrl::parse(&mock.url()).unwrap();
12141219

1215-
let relay = new_relay(url, RelayOptions::default().ban_relay_on_mismatch(true));
1220+
let relay = new_relay(
1221+
url,
1222+
RelayOptions::default()
1223+
.verify_subscriptions(true)
1224+
.ban_relay_on_mismatch(true),
1225+
);
12161226

12171227
assert_eq!(relay.status(), RelayStatus::Initialized);
12181228

crates/nostr-relay-pool/src/relay/options.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub struct RelayOptions {
2323
pub(super) idle_timeout: Duration,
2424
pub(super) retry_interval: Duration,
2525
pub(super) adjust_retry_interval: bool,
26+
pub(super) verify_subscriptions: bool,
2627
pub(super) ban_relay_on_mismatch: bool,
2728
pub(super) limits: RelayLimits,
2829
pub(super) max_avg_latency: Option<Duration>,
@@ -39,6 +40,7 @@ impl Default for RelayOptions {
3940
idle_timeout: Duration::from_secs(300),
4041
retry_interval: DEFAULT_RETRY_INTERVAL,
4142
adjust_retry_interval: true,
43+
verify_subscriptions: false,
4244
ban_relay_on_mismatch: false,
4345
limits: RelayLimits::default(),
4446
max_avg_latency: None,
@@ -115,6 +117,12 @@ impl RelayOptions {
115117
self
116118
}
117119

120+
/// Verify that received events belong to a subscription and match the filter.
121+
pub fn verify_subscriptions(mut self, enable: bool) -> Self {
122+
self.verify_subscriptions = enable;
123+
self
124+
}
125+
118126
/// If true, ban a relay when it sends an event that doesn't match the subscription filter.
119127
pub fn ban_relay_on_mismatch(mut self, ban_relay: bool) -> Self {
120128
self.ban_relay_on_mismatch = ban_relay;

0 commit comments

Comments
 (0)