From 26b0974901b1ec9d46816b92f90ac8eb8c367763 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 23 Jan 2024 15:46:19 +0000 Subject: [PATCH] Timestamp NWC filters --- mutiny-core/src/lib.rs | 2 +- mutiny-core/src/nostr/mod.rs | 25 ++++++++++++++++++++----- mutiny-core/src/nostr/nwc.rs | 5 +++-- mutiny-core/src/storage.rs | 15 +++++++++++++++ mutiny-core/src/utils.rs | 31 +++++++++++++++++++++++++++++-- 5 files changed, 68 insertions(+), 10 deletions(-) diff --git a/mutiny-core/src/lib.rs b/mutiny-core/src/lib.rs index 33e659dfb..6b4cc6446 100644 --- a/mutiny-core/src/lib.rs +++ b/mutiny-core/src/lib.rs @@ -953,7 +953,7 @@ impl MutinyWallet { _ = filter_check_fut => { // Check if the filters have changed if let Ok(current_filters) = nostr.get_filters() { - if current_filters != last_filters { + if !utils::compare_filters_vec(¤t_filters, &last_filters) { log_debug!(logger, "subscribing to new nwc filters"); client.subscribe(current_filters.clone()).await; last_filters = current_filters; diff --git a/mutiny-core/src/nostr/mod.rs b/mutiny-core/src/nostr/mod.rs index 5d6389d3a..803593da4 100644 --- a/mutiny-core/src/nostr/mod.rs +++ b/mutiny-core/src/nostr/mod.rs @@ -132,14 +132,27 @@ impl NostrManager { relays } - fn get_nwc_filters(&self) -> Vec { - self.nwc + fn get_nwc_filters(&self) -> Result, MutinyError> { + // if we haven't synced before, use now and save to storage + let time_stamp = match self.storage.get_nwc_sync_time()? { + None => { + let now = Timestamp::now(); + self.storage.set_nwc_sync_time(now.as_u64())?; + now + } + Some(time) => Timestamp::from(time), + }; + + let vec = self + .nwc .read() .unwrap() .iter() .filter(|x| x.profile.active()) - .map(|nwc| nwc.create_nwc_filter()) - .collect() + .map(|nwc| nwc.create_nwc_filter(time_stamp)) + .collect(); + + Ok(vec) } /// Filters for getting DMs from our contacts @@ -168,7 +181,7 @@ impl NostrManager { } pub fn get_filters(&self) -> Result, MutinyError> { - let mut nwc = self.get_nwc_filters(); + let mut nwc = self.get_nwc_filters()?; let dm = self.get_dm_filter()?; nwc.push(dm); @@ -918,6 +931,8 @@ impl NostrManager { .cloned() }; + self.storage.set_nwc_sync_time(event.created_at.as_u64())?; + if let Some(mut nwc) = nwc { let event = nwc.handle_nwc_request(event, invoice_handler, self).await?; Ok(event) diff --git a/mutiny-core/src/nostr/nwc.rs b/mutiny-core/src/nostr/nwc.rs index 81860b69f..5c748a774 100644 --- a/mutiny-core/src/nostr/nwc.rs +++ b/mutiny-core/src/nostr/nwc.rs @@ -17,7 +17,7 @@ use lightning_invoice::Bolt11Invoice; use nostr::key::XOnlyPublicKey; use nostr::nips::nip47::*; use nostr::prelude::{decrypt, encrypt}; -use nostr::{Event, EventBuilder, EventId, Filter, JsonUtil, Keys, Kind, Tag}; +use nostr::{Event, EventBuilder, EventId, Filter, JsonUtil, Keys, Kind, Tag, Timestamp}; use serde::{Deserialize, Serialize}; use std::cmp::Ordering; use std::str::FromStr; @@ -266,11 +266,12 @@ impl NostrWalletConnect { self.server_key.public_key() } - pub fn create_nwc_filter(&self) -> Filter { + pub fn create_nwc_filter(&self, timestamp: Timestamp) -> Filter { Filter::new() .kinds(vec![Kind::WalletConnectRequest]) .author(self.client_pubkey()) .pubkey(self.server_pubkey()) + .since(timestamp) } /// Create Nostr Wallet Connect Info event diff --git a/mutiny-core/src/storage.rs b/mutiny-core/src/storage.rs index 59f6b285b..1ad82bf82 100644 --- a/mutiny-core/src/storage.rs +++ b/mutiny-core/src/storage.rs @@ -33,6 +33,7 @@ pub const FEDERATIONS_KEY: &str = "federations"; const FEE_ESTIMATES_KEY: &str = "fee_estimates"; pub const BITCOIN_PRICE_CACHE_KEY: &str = "bitcoin_price_cache"; const FIRST_SYNC_KEY: &str = "first_sync"; +pub const LAST_NWC_SYNC_TIME_KEY: &str = "last_nwc_sync_time"; pub(crate) const DEVICE_ID_KEY: &str = "device_id"; pub const DEVICE_LOCK_KEY: &str = "device_lock"; pub(crate) const EXPECTED_NETWORK_KEY: &str = "network"; @@ -424,6 +425,20 @@ pub trait MutinyStorage: Clone + Sized + Send + Sync + 'static { } } + fn get_nwc_sync_time(&self) -> Result, MutinyError> { + self.get_data(LAST_NWC_SYNC_TIME_KEY) + } + + fn set_nwc_sync_time(&self, time: u64) -> Result<(), MutinyError> { + // only update if the time is newer + let current = self.get_nwc_sync_time()?.unwrap_or_default(); + if current < time { + self.set_data(LAST_NWC_SYNC_TIME_KEY.to_string(), time, None) + } else { + Ok(()) + } + } + fn get_device_id(&self) -> Result { match self.get_data(DEVICE_ID_KEY)? { Some(id) => Ok(id), diff --git a/mutiny-core/src/utils.rs b/mutiny-core/src/utils.rs index c818dc584..3924a94cf 100644 --- a/mutiny-core/src/utils.rs +++ b/mutiny-core/src/utils.rs @@ -12,10 +12,10 @@ use lightning::util::ser::Writeable; use lightning::util::ser::Writer; use nostr::key::XOnlyPublicKey; use nostr::nips::nip05; -use nostr::{Event, FromBech32, JsonUtil, Metadata}; +use nostr::{Event, Filter, FromBech32, JsonUtil, Kind, Metadata}; use reqwest::Client; use serde_json::Value; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::str::FromStr; pub const FETCH_TIMEOUT: i32 = 30_000; @@ -213,6 +213,33 @@ pub async fn parse_npub_or_nip05(str: &str) -> Result bool { + if a.len() != b.len() { + return false; + } + + // compare that we have all the same kinds + let agg_kinds_a: HashSet = a.iter().flat_map(|i| i.kinds.clone()).collect(); + let agg_kinds_b: HashSet = b.iter().flat_map(|i| i.kinds.clone()).collect(); + + if agg_kinds_a != agg_kinds_b { + return false; + } + + // compare same authors + let agg_authors_a: HashSet = a.iter().flat_map(|i| i.authors.clone()).collect(); + let agg_authors_b: HashSet = b.iter().flat_map(|i| i.authors.clone()).collect(); + + if agg_authors_a != agg_authors_b { + return false; + } + + // if we have the same authors and kinds they are effectively the same filters to us + true +} + /// Returns the version of a channel monitor from a serialized version /// of a channel monitor. pub fn get_monitor_version(bytes: &[u8]) -> u64 {