Skip to content

Commit

Permalink
Optimize label activity
Browse files Browse the repository at this point in the history
  • Loading branch information
benthecarman committed Apr 5, 2024
1 parent 2526f60 commit 74dd6ba
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 59 deletions.
66 changes: 59 additions & 7 deletions mutiny-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ pub use crate::gossip::{GOSSIP_SYNC_TIME_KEY, NETWORK_GRAPH_KEY, PROB_SCORER_KEY
pub use crate::keymanager::generate_seed;
pub use crate::ldkstorage::{CHANNEL_CLOSURE_PREFIX, CHANNEL_MANAGER_KEY, MONITORS_PREFIX_KEY};
use crate::storage::{
list_payment_info, persist_payment_info, update_nostr_contact_list, IndexItem, MutinyStorage,
DEVICE_ID_KEY, EXPECTED_NETWORK_KEY, NEED_FULL_SYNC_KEY, ONCHAIN_PREFIX,
PAYMENT_INBOUND_PREFIX_KEY, PAYMENT_OUTBOUND_PREFIX_KEY, SUBSCRIPTION_TIMESTAMP,
get_payment_hash_from_key, list_payment_info, persist_payment_info, update_nostr_contact_list,
IndexItem, MutinyStorage, DEVICE_ID_KEY, EXPECTED_NETWORK_KEY, NEED_FULL_SYNC_KEY,
ONCHAIN_PREFIX, PAYMENT_INBOUND_PREFIX_KEY, PAYMENT_OUTBOUND_PREFIX_KEY,
SUBSCRIPTION_TIMESTAMP,
};
use crate::{auth::MutinyAuthClient, hermes::HermesClient, logging::MutinyLogger};
use crate::{blindauth::BlindAuthClient, cashu::CashuHttpClient};
Expand Down Expand Up @@ -114,6 +115,7 @@ use nostr_sdk::{NostrSigner, RelayPoolNotification};
use reqwest::multipart::{Form, Part};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashSet;
use std::sync::Arc;
#[cfg(not(target_arch = "wasm32"))]
use std::time::Instant;
Expand Down Expand Up @@ -1720,10 +1722,7 @@ impl<S: MutinyStorage> MutinyWallet<S> {
true => PAYMENT_INBOUND_PREFIX_KEY,
false => PAYMENT_OUTBOUND_PREFIX_KEY,
};
let payment_hash_str = key
.trim_start_matches(prefix)
.splitn(2, '_') // To support the old format that had `_{node_id}` at the end
.collect::<Vec<&str>>()[0];
let payment_hash_str = get_payment_hash_from_key(key, prefix);
let hash: [u8; 32] = FromHex::from_hex(payment_hash_str)?;

return MutinyInvoice::from(info, PaymentHash(hash), inbound, labels).map(Some);
Expand Down Expand Up @@ -1810,6 +1809,59 @@ impl<S: MutinyStorage> MutinyWallet<S> {
Ok(activities)
}

/// Returns all the lightning activity for a given label
pub async fn get_label_activity(
&self,
label: &String,
) -> Result<Vec<ActivityItem>, MutinyError> {
let Some(label_item) = self.node_manager.get_label(label)? else {
return Ok(Vec::new());
};

// get all the payment hashes for this label
let payment_hashes: HashSet<sha256::Hash> = label_item
.invoices
.into_iter()
.map(|i| *i.payment_hash())
.collect();

let index = self.storage.activity_index();
let index = index.try_read()?.clone().into_iter().collect_vec();

let labels_map = self.storage.get_invoice_labels()?;

let mut activities = Vec::with_capacity(index.len());
for item in index {
if item.key.starts_with(PAYMENT_INBOUND_PREFIX_KEY) {
let payment_hash_str =
get_payment_hash_from_key(&item.key, PAYMENT_INBOUND_PREFIX_KEY);
let hash = sha256::Hash::from_str(payment_hash_str)?;

if payment_hashes.contains(&hash) {
if let Some(mutiny_invoice) =
self.get_invoice_internal(&item.key, true, &labels_map)?
{
activities.push(ActivityItem::Lightning(Box::new(mutiny_invoice)));
}
}
} else if item.key.starts_with(PAYMENT_OUTBOUND_PREFIX_KEY) {
let payment_hash_str =
get_payment_hash_from_key(&item.key, PAYMENT_OUTBOUND_PREFIX_KEY);
let hash = sha256::Hash::from_str(payment_hash_str)?;

if payment_hashes.contains(&hash) {
if let Some(mutiny_invoice) =
self.get_invoice_internal(&item.key, true, &labels_map)?
{
activities.push(ActivityItem::Lightning(Box::new(mutiny_invoice)));
}
}
}
}

Ok(activities)
}

pub fn list_invoices(&self) -> Result<Vec<MutinyInvoice>, MutinyError> {
let mut inbound_invoices = self.list_payment_info_from_persisters(true)?;
let mut outbound_invoices = self.list_payment_info_from_persisters(false)?;
Expand Down
49 changes: 2 additions & 47 deletions mutiny-core/src/nodemanager.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use crate::auth::MutinyAuthClient;
use crate::event::HTLCStatus;
use crate::labels::LabelStorage;
use crate::ldkstorage::CHANNEL_CLOSURE_PREFIX;
use crate::logging::LOGGING_KEY;
use crate::utils::{sleep, spawn};
use crate::ActivityItem;
use crate::MutinyInvoice;
use crate::MutinyWalletConfig;
use crate::{
Expand Down Expand Up @@ -966,47 +964,6 @@ impl<S: MutinyStorage> NodeManager<S> {
Ok(details_opt.map(|(d, _)| d))
}

/// Returns all the on-chain and lightning activity for a given label
pub async fn get_label_activity(
&self,
label: &String,
) -> Result<Vec<ActivityItem>, MutinyError> {
let Some(label_item) = self.get_label(label)? else {
return Ok(Vec::new());
};

let mut activity = vec![];
for inv in label_item.invoices.iter() {
if let Ok(ln) = self.get_invoice_by_hash(inv.payment_hash()).await {
// Only show paid and in-flight invoices
match ln.status {
HTLCStatus::Succeeded | HTLCStatus::InFlight => {
activity.push(ActivityItem::Lightning(Box::new(ln)));
}
HTLCStatus::Pending | HTLCStatus::Failed => {}
}
}
}
let onchain = self
.list_onchain()
.map_err(|e| {
log_warn!(self.logger, "Failed to get bdk history: {e}");
e
})
.unwrap_or_default();

for on in onchain {
if on.labels.contains(label) {
activity.push(ActivityItem::OnChain(on));
}
}

// Newest first
activity.sort_by(|a, b| b.cmp(a));

Ok(activity)
}

/// Adds labels to the TransactionDetails based on the address labels.
/// This will panic if the TransactionDetails does not have a transaction.
/// Make sure you flag `include_raw` when calling `list_transactions` to
Expand Down Expand Up @@ -2113,10 +2070,8 @@ pub fn create_lsp_config(
mod tests {
use crate::{
encrypt::encryption_key_from_pass,
nodemanager::{
ActivityItem, ChannelClosure, MutinyInvoice, NodeManager, TransactionDetails,
},
MutinyWalletConfigBuilder, PrivacyLevel,
nodemanager::{ChannelClosure, MutinyInvoice, NodeManager, TransactionDetails},
ActivityItem, MutinyWalletConfigBuilder, PrivacyLevel,
};
use crate::{keymanager::generate_seed, nodemanager::NodeManagerBuilder};
use bdk::chain::ConfirmationTime;
Expand Down
11 changes: 7 additions & 4 deletions mutiny-core/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -986,10 +986,7 @@ pub(crate) fn list_payment_info<S: MutinyStorage>(
Ok(map
.into_iter()
.map(|(key, value)| {
let payment_hash_str = key
.trim_start_matches(prefix)
.splitn(2, '_') // To support the old format that had `_{node_id}` at the end
.collect::<Vec<&str>>()[0];
let payment_hash_str = get_payment_hash_from_key(key.as_str(), prefix);
let hash: [u8; 32] =
FromHex::from_hex(payment_hash_str).expect("key should be a sha256 hash");
(PaymentHash(hash), value)
Expand Down Expand Up @@ -1057,6 +1054,12 @@ where
}
}

pub(crate) fn get_payment_hash_from_key<'a>(key: &'a str, prefix: &str) -> &'a str {
key.trim_start_matches(prefix)
.splitn(2, '_') // To support the old format that had `_{node_id}` at the end
.collect::<Vec<&str>>()[0]
}

#[cfg(test)]
mod tests {
use crate::test_utils::*;
Expand Down
2 changes: 1 addition & 1 deletion mutiny-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1180,7 +1180,7 @@ impl MutinyWallet {
label: String,
) -> Result<JsValue /* Vec<ActivityItem> */, MutinyJsError> {
// get activity from the node manager
let activity = self.inner.node_manager.get_label_activity(&label).await?;
let activity = self.inner.get_label_activity(&label).await?;
let mut activity: Vec<ActivityItem> = activity.into_iter().map(|a| a.into()).collect();

// add contact to the activity item it has one, otherwise return the activity list
Expand Down

0 comments on commit 74dd6ba

Please sign in to comment.