From e77a11da5729788dab8556d460ec6d1b4a791d6c Mon Sep 17 00:00:00 2001 From: benthecarman Date: Mon, 29 Jan 2024 22:10:29 +0000 Subject: [PATCH] Fix labeling --- mutiny-core/src/lib.rs | 4 +--- mutiny-core/src/node.rs | 44 ++++++++++++++++++++++++++++++---- mutiny-core/src/nodemanager.rs | 10 ++++++-- mutiny-wasm/src/lib.rs | 19 +++++++-------- 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/mutiny-core/src/lib.rs b/mutiny-core/src/lib.rs index 5a956a17a..1773e7c24 100644 --- a/mutiny-core/src/lib.rs +++ b/mutiny-core/src/lib.rs @@ -1142,9 +1142,7 @@ impl MutinyWallet { } // Fallback to node_manager invoice creation if no federation invoice created - let inv = self.node_manager.create_invoice(amount).await?; - self.storage - .set_invoice_labels(inv.bolt11.clone().expect("just created"), labels)?; + let inv = self.node_manager.create_invoice(amount, labels).await?; Ok(inv) } diff --git a/mutiny-core/src/node.rs b/mutiny-core/src/node.rs index 1b67a6c67..9a7af3d4d 100644 --- a/mutiny-core/src/node.rs +++ b/mutiny-core/src/node.rs @@ -973,6 +973,7 @@ impl Node { &self, amount_sat: Option, route_hints: Option>, + labels: Vec, ) -> Result { match self.lsp_client.as_ref() { Some(lsp) => { @@ -1044,6 +1045,7 @@ impl Node { Some(amount_minus_fee), Some(lsp_fee.fee_amount_msat), route_hints, + labels, ) .await?; @@ -1080,7 +1082,12 @@ impl Node { AnyLsp::Lsps(client) => { if has_inbound_capacity { Ok(self - .create_internal_invoice(Some(amount_sat), None, route_hints) + .create_internal_invoice( + Some(amount_sat), + None, + route_hints, + labels, + ) .await?) } else { let lsp_invoice = match client @@ -1096,6 +1103,7 @@ impl Node { invoice.clone(), Some(amount_sat * 1_000), Some(lsp_fee.fee_amount_msat), + labels, ) .await?; @@ -1112,7 +1120,7 @@ impl Node { } } None => Ok(self - .create_internal_invoice(amount_sat, None, route_hints) + .create_internal_invoice(amount_sat, None, route_hints, labels) .await?), } } @@ -1122,6 +1130,7 @@ impl Node { amount_sat: Option, fee_amount_msat: Option, route_hints: Option>, + labels: Vec, ) -> Result { let amount_msat = amount_sat.map(|s| s * 1_000); // Set description to empty string to make smallest possible invoice/QR code @@ -1175,7 +1184,7 @@ impl Node { MutinyError::InvoiceCreationFailed })?; - self.save_invoice_payment_info(invoice.clone(), amount_msat, fee_amount_msat) + self.save_invoice_payment_info(invoice.clone(), amount_msat, fee_amount_msat, labels) .await?; log_info!(self.logger, "SUCCESS: generated invoice: {invoice}"); @@ -1188,6 +1197,7 @@ impl Node { invoice: Bolt11Invoice, amount_msat: Option, fee_amount_msat: Option, + labels: Vec, ) -> Result<(), MutinyError> { let last_update = utils::now().as_secs(); let payment_hash = PaymentHash(invoice.payment_hash().into_inner()); @@ -1212,6 +1222,8 @@ impl Node { MutinyError::InvoiceCreationFailed })?; + self.persister.storage.set_invoice_labels(invoice, labels)?; + Ok(()) } @@ -2546,6 +2558,7 @@ mod tests { #[cfg(target_arch = "wasm32")] mod wasm_test { use crate::event::{MillisatAmount, PaymentInfo}; + use crate::labels::LabelStorage; use crate::storage::MemoryStorage; use crate::test_utils::create_node; use crate::HTLCStatus; @@ -2573,8 +2586,13 @@ mod wasm_test { let now = crate::utils::now().as_secs(); let amount_sats = 1_000; + let label = "test".to_string(); + let labels = vec![label.clone()]; - let invoice = node.create_invoice(Some(amount_sats), None).await.unwrap(); + let invoice = node + .create_invoice(Some(amount_sats), None, labels.clone()) + .await + .unwrap(); assert_eq!(invoice.amount_milli_satoshis(), Some(amount_sats * 1000)); match invoice.description() { @@ -2596,8 +2614,21 @@ mod wasm_test { assert_eq!(from_storage.amount_sats, Some(amount_sats)); assert_eq!(from_storage.status, HTLCStatus::Pending); assert_eq!(from_storage.fees_paid, None); + assert_eq!(from_storage.labels, labels.clone()); assert!(from_storage.inbound); assert!(from_storage.last_updated >= now); + + // check labels + + let invoice_labels = storage.get_invoice_labels().unwrap(); + assert_eq!(invoice_labels.len(), 1); + assert_eq!(invoice_labels.get(&invoice).cloned(), Some(labels)); + + let label_item = storage.get_label("test").unwrap().unwrap(); + + assert!(label_item.last_used_time >= now); + assert!(label_item.addresses.is_empty()); + assert_eq!(label_item.invoices, vec![invoice]); } #[test] @@ -2605,7 +2636,10 @@ mod wasm_test { let storage = MemoryStorage::default(); let node = create_node(storage).await; - let invoice = node.create_invoice(Some(10_000), None).await.unwrap(); + let invoice = node + .create_invoice(Some(10_000), None, vec![]) + .await + .unwrap(); let result = node .pay_invoice_with_timeout(&invoice, None, None, vec![]) diff --git a/mutiny-core/src/nodemanager.rs b/mutiny-core/src/nodemanager.rs index e0a15ccb1..c304585be 100644 --- a/mutiny-core/src/nodemanager.rs +++ b/mutiny-core/src/nodemanager.rs @@ -1370,7 +1370,11 @@ impl NodeManager { /// /// If the manager has more than one node it will create a phantom invoice. /// If there is only one node it will create an invoice just for that node. - pub async fn create_invoice(&self, amount: Option) -> Result { + pub async fn create_invoice( + &self, + amount: Option, + labels: Vec, + ) -> Result { let nodes = self.nodes.lock().await; let use_phantom = nodes.len() > 1 && self.lsp_config.is_none(); if nodes.len() == 0 { @@ -1393,7 +1397,9 @@ impl NodeManager { } else { return Err(MutinyError::WalletOperationFailed); }; - let invoice = first_node.create_invoice(amount, route_hints).await?; + let invoice = first_node + .create_invoice(amount, route_hints, labels) + .await?; Ok(invoice.into()) } diff --git a/mutiny-wasm/src/lib.rs b/mutiny-wasm/src/lib.rs index 1b17ea0b5..94af7ba80 100644 --- a/mutiny-wasm/src/lib.rs +++ b/mutiny-wasm/src/lib.rs @@ -1051,20 +1051,17 @@ impl MutinyWallet { let activity = self.inner.node_manager.get_label_activity(&label).await?; let mut activity: Vec = activity.into_iter().map(|a| a.into()).collect(); - // add contact to the activity item if it is one - let Some(contact) = self.inner.node_manager.get_contact(&label)? else { - return Ok(JsValue::from_serde(&activity)?); + // add contact to the activity item it has one, otherwise return the activity list + let contact = match self.inner.node_manager.get_contact(&label)? { + Some(contact) => contact, + None => return Ok(JsValue::from_serde(&activity)?), }; + // if we have a contact, add it to the activity item, remove it as a label + // This is the same as we do in get_activity for a in activity.iter_mut() { - // find labels that have a contact and add them to the item - for a_label in a.labels.iter() { - if label == *a_label { - a.contacts - .push(TagItem::from((a_label.clone(), contact.clone()))); - } - } - // remove labels that have the contact to prevent duplicates + a.contacts + .push(TagItem::from((label.clone(), contact.clone()))); a.labels.retain(|l| l != &label); }