Skip to content
This repository was archived by the owner on Feb 3, 2025. It is now read-only.

Commit 15ecc36

Browse files
committed
Bolt 12
1 parent c0ce5b5 commit 15ecc36

File tree

12 files changed

+583
-90
lines changed

12 files changed

+583
-90
lines changed

mutiny-core/src/error.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::esplora::TxSyncError;
22
use aes::cipher::block_padding::UnpadError;
33
use bitcoin::Network;
44
use lightning::ln::peer_handler::PeerHandleError;
5+
use lightning::offers::parse::Bolt12SemanticError;
56
use lightning_invoice::payment::PaymentError;
67
use lightning_invoice::ParseOrSemanticError;
78
use lightning_rapid_gossip_sync::GraphSyncError;
@@ -446,3 +447,26 @@ impl From<nostr::event::builder::Error> for MutinyError {
446447
Self::NostrError
447448
}
448449
}
450+
451+
impl From<Bolt12SemanticError> for MutinyError {
452+
fn from(e: Bolt12SemanticError) -> Self {
453+
match e {
454+
Bolt12SemanticError::UnsupportedChain => MutinyError::NetworkMismatch,
455+
Bolt12SemanticError::UnexpectedChain => MutinyError::NetworkMismatch,
456+
Bolt12SemanticError::MissingAmount => MutinyError::BadAmountError,
457+
Bolt12SemanticError::InvalidAmount => MutinyError::BadAmountError,
458+
Bolt12SemanticError::InsufficientAmount => MutinyError::BadAmountError,
459+
Bolt12SemanticError::UnexpectedAmount => MutinyError::BadAmountError,
460+
Bolt12SemanticError::UnsupportedCurrency => MutinyError::BadAmountError,
461+
Bolt12SemanticError::MissingSigningPubkey => MutinyError::PubkeyInvalid,
462+
Bolt12SemanticError::InvalidSigningPubkey => MutinyError::PubkeyInvalid,
463+
Bolt12SemanticError::UnexpectedSigningPubkey => MutinyError::PubkeyInvalid,
464+
Bolt12SemanticError::MissingQuantity => MutinyError::BadAmountError,
465+
Bolt12SemanticError::InvalidQuantity => MutinyError::BadAmountError,
466+
Bolt12SemanticError::UnexpectedQuantity => MutinyError::BadAmountError,
467+
Bolt12SemanticError::MissingPaths => MutinyError::RoutingFailed,
468+
Bolt12SemanticError::AlreadyExpired => MutinyError::PaymentTimeout,
469+
_ => MutinyError::LnDecodeError,
470+
}
471+
}
472+
}

mutiny-core/src/event.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ pub(crate) struct PaymentInfo {
2828
#[serde(skip_serializing_if = "Option::is_none")]
2929
pub preimage: Option<[u8; 32]>,
3030
#[serde(skip_serializing_if = "Option::is_none")]
31+
pub payment_hash: Option<String>,
32+
#[serde(skip_serializing_if = "Option::is_none")]
3133
pub secret: Option<[u8; 32]>,
3234
pub status: HTLCStatus,
3335
#[serde(skip_serializing_if = "MillisatAmount::is_none")]
@@ -37,6 +39,8 @@ pub(crate) struct PaymentInfo {
3739
#[serde(skip_serializing_if = "Option::is_none")]
3840
pub bolt11: Option<Bolt11Invoice>,
3941
#[serde(skip_serializing_if = "Option::is_none")]
42+
pub bolt12: Option<String>,
43+
#[serde(skip_serializing_if = "Option::is_none")]
4044
pub payee_pubkey: Option<PublicKey>,
4145
pub last_update: u64,
4246
}
@@ -266,6 +270,8 @@ impl<S: MutinyStorage> EventHandler<S> {
266270
let payment_secret = payment_secret.map(|p| p.0);
267271
saved_payment_info.status = HTLCStatus::Succeeded;
268272
saved_payment_info.preimage = payment_preimage;
273+
// set payment_hash, we won't have it yet for bolt 12
274+
saved_payment_info.payment_hash = Some(payment_hash.0.to_hex());
269275
saved_payment_info.secret = payment_secret;
270276
saved_payment_info.amt_msat = MillisatAmount(Some(amount_msat));
271277
saved_payment_info.last_update = crate::utils::now().as_secs();
@@ -288,12 +294,14 @@ impl<S: MutinyStorage> EventHandler<S> {
288294

289295
let payment_info = PaymentInfo {
290296
preimage: payment_preimage,
297+
payment_hash: Some(payment_hash.0.to_hex()),
291298
secret: payment_secret,
292299
status: HTLCStatus::Succeeded,
293300
amt_msat: MillisatAmount(Some(amount_msat)),
294301
fee_paid_msat: None,
295302
payee_pubkey: receiver_node_id,
296303
bolt11: None,
304+
bolt12: None,
297305
last_update,
298306
};
299307
match self.persister.persist_payment_info(
@@ -311,28 +319,39 @@ impl<S: MutinyStorage> EventHandler<S> {
311319
}
312320
}
313321
Event::PaymentSent {
322+
payment_id,
314323
payment_preimage,
315324
payment_hash,
316325
fee_paid_msat,
317-
..
318326
} => {
319327
log_debug!(
320328
self.logger,
321329
"EVENT: PaymentSent: {}",
322330
payment_hash.0.to_hex()
323331
);
324332

325-
match self
333+
// lookup by payment hash then payment id, we use payment_id for bolt 12
334+
let mut lookup_id = payment_hash.0;
335+
let found_payment_info = self
326336
.persister
327-
.read_payment_info(&payment_hash.0, false, &self.logger)
328-
{
337+
.read_payment_info(&lookup_id, false, &self.logger)
338+
.or_else(|| {
339+
payment_id.and_then(|id| {
340+
lookup_id = id.0;
341+
self.persister.read_payment_info(&id.0, false, &self.logger)
342+
})
343+
});
344+
345+
match found_payment_info {
329346
Some(mut saved_payment_info) => {
330347
saved_payment_info.status = HTLCStatus::Succeeded;
331348
saved_payment_info.preimage = Some(payment_preimage.0);
349+
// bolt 12 won't have the payment hash set yet
350+
saved_payment_info.payment_hash = Some(payment_hash.0.to_hex());
332351
saved_payment_info.fee_paid_msat = fee_paid_msat;
333352
saved_payment_info.last_update = crate::utils::now().as_secs();
334353
match self.persister.persist_payment_info(
335-
&payment_hash.0,
354+
&lookup_id,
336355
&saved_payment_info,
337356
false,
338357
) {
@@ -666,10 +685,12 @@ mod test {
666685

667686
let payment_info = PaymentInfo {
668687
preimage: Some(preimage),
688+
payment_hash: None,
669689
status: HTLCStatus::Succeeded,
670690
amt_msat: MillisatAmount(Some(420)),
671691
fee_paid_msat: None,
672692
bolt11: None,
693+
bolt12: None,
673694
payee_pubkey: Some(pubkey),
674695
secret: None,
675696
last_update: utils::now().as_secs(),

mutiny-core/src/labels.rs

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use crate::error::MutinyError;
22
use crate::nodemanager::NodeManager;
33
use crate::storage::MutinyStorage;
44
use bitcoin::{Address, XOnlyPublicKey};
5-
use lightning_invoice::Bolt11Invoice;
65
use lnurl::lightning_address::LightningAddress;
76
use lnurl::lnurl::LnUrl;
87
use nostr::Metadata;
@@ -21,7 +20,7 @@ pub struct LabelItem {
2120
/// List of addresses that have this label
2221
pub addresses: Vec<Address>,
2322
/// List of invoices that have this label
24-
pub invoices: Vec<Bolt11Invoice>,
23+
pub invoices: Vec<String>,
2524
/// Epoch time in seconds when this label was last used
2625
pub last_used_time: u64,
2726
}
@@ -96,7 +95,7 @@ pub trait LabelStorage {
9695
/// Get a map of addresses to labels. This can be used to get all the labels for an address
9796
fn get_address_labels(&self) -> Result<HashMap<String, Vec<String>>, MutinyError>;
9897
/// Get a map of invoices to labels. This can be used to get all the labels for an invoice
99-
fn get_invoice_labels(&self) -> Result<HashMap<Bolt11Invoice, Vec<String>>, MutinyError>;
98+
fn get_invoice_labels(&self) -> Result<HashMap<String, Vec<String>>, MutinyError>;
10099
/// Get all the existing labels
101100
fn get_labels(&self) -> Result<HashMap<String, LabelItem>, MutinyError>;
102101
/// Get information about a label
@@ -108,11 +107,7 @@ pub trait LabelStorage {
108107
/// Set the labels for an invoice, replacing any existing labels
109108
/// If you do not want to replace any existing labels, use `get_invoice_labels` to get the existing labels,
110109
/// add the new labels, and then use `set_invoice_labels` to set the new labels
111-
fn set_invoice_labels(
112-
&self,
113-
invoice: Bolt11Invoice,
114-
labels: Vec<String>,
115-
) -> Result<(), MutinyError>;
110+
fn set_invoice_labels(&self, invoice: String, labels: Vec<String>) -> Result<(), MutinyError>;
116111
/// Get all the existing contacts
117112
fn get_contacts(&self) -> Result<HashMap<String, Contact>, MutinyError>;
118113
/// Get a contact by label, the label should be a uuid
@@ -139,9 +134,8 @@ impl<S: MutinyStorage> LabelStorage for S {
139134
Ok(res.unwrap_or_default()) // if no labels exist, return an empty map
140135
}
141136

142-
fn get_invoice_labels(&self) -> Result<HashMap<Bolt11Invoice, Vec<String>>, MutinyError> {
143-
let res: Option<HashMap<Bolt11Invoice, Vec<String>>> =
144-
self.get_data(INVOICE_LABELS_MAP_KEY)?;
137+
fn get_invoice_labels(&self) -> Result<HashMap<String, Vec<String>>, MutinyError> {
138+
let res: Option<HashMap<String, Vec<String>>> = self.get_data(INVOICE_LABELS_MAP_KEY)?;
145139
Ok(res.unwrap_or_default()) // if no labels exist, return an empty map
146140
}
147141

@@ -207,11 +201,7 @@ impl<S: MutinyStorage> LabelStorage for S {
207201
Ok(())
208202
}
209203

210-
fn set_invoice_labels(
211-
&self,
212-
invoice: Bolt11Invoice,
213-
labels: Vec<String>,
214-
) -> Result<(), MutinyError> {
204+
fn set_invoice_labels(&self, invoice: String, labels: Vec<String>) -> Result<(), MutinyError> {
215205
// update the labels map
216206
let mut invoice_labels = self.get_invoice_labels()?;
217207
invoice_labels.insert(invoice.clone(), labels.clone());
@@ -397,7 +387,7 @@ impl<S: MutinyStorage> LabelStorage for NodeManager<S> {
397387
self.storage.get_address_labels()
398388
}
399389

400-
fn get_invoice_labels(&self) -> Result<HashMap<Bolt11Invoice, Vec<String>>, MutinyError> {
390+
fn get_invoice_labels(&self) -> Result<HashMap<String, Vec<String>>, MutinyError> {
401391
self.storage.get_invoice_labels()
402392
}
403393

@@ -413,11 +403,7 @@ impl<S: MutinyStorage> LabelStorage for NodeManager<S> {
413403
self.storage.set_address_labels(address, labels)
414404
}
415405

416-
fn set_invoice_labels(
417-
&self,
418-
invoice: Bolt11Invoice,
419-
labels: Vec<String>,
420-
) -> Result<(), MutinyError> {
406+
fn set_invoice_labels(&self, invoice: String, labels: Vec<String>) -> Result<(), MutinyError> {
421407
self.storage.set_invoice_labels(invoice, labels)
422408
}
423409

@@ -459,7 +445,6 @@ mod tests {
459445
use super::*;
460446
use crate::test_utils::*;
461447
use bitcoin::Address;
462-
use lightning_invoice::Bolt11Invoice;
463448
use std::collections::HashMap;
464449
use std::str::FromStr;
465450

@@ -487,18 +472,18 @@ mod tests {
487472
labels
488473
}
489474

490-
fn create_test_invoice_labels_map() -> HashMap<Bolt11Invoice, Vec<String>> {
475+
fn create_test_invoice_labels_map() -> HashMap<String, Vec<String>> {
491476
let mut labels = HashMap::new();
492477
labels.insert(
493-
Bolt11Invoice::from_str("lnbc923720n1pj9nrefpp5pczykgk37af5388n8dzynljpkzs7sje4melqgazlwv9y3apay8jqhp5rd8saxz3juve3eejq7z5fjttxmpaq88d7l92xv34n4h3mq6kwq2qcqzzsxqzfvsp5z0jwpehkuz9f2kv96h62p8x30nku76aj8yddpcust7g8ad0tr52q9qyyssqfy622q25helv8cj8hyxqltws4rdwz0xx2hw0uh575mn7a76cp3q4jcptmtjkjs4a34dqqxn8uy70d0qlxqleezv4zp84uk30pp5q3nqq4c9gkz").unwrap(),
478+
String::from("lnbc923720n1pj9nrefpp5pczykgk37af5388n8dzynljpkzs7sje4melqgazlwv9y3apay8jqhp5rd8saxz3juve3eejq7z5fjttxmpaq88d7l92xv34n4h3mq6kwq2qcqzzsxqzfvsp5z0jwpehkuz9f2kv96h62p8x30nku76aj8yddpcust7g8ad0tr52q9qyyssqfy622q25helv8cj8hyxqltws4rdwz0xx2hw0uh575mn7a76cp3q4jcptmtjkjs4a34dqqxn8uy70d0qlxqleezv4zp84uk30pp5q3nqq4c9gkz"),
494479
vec!["test1".to_string()],
495480
);
496481
labels.insert(
497-
Bolt11Invoice::from_str("lnbc923720n1pj9nre4pp58zjsgd3xkyj33wv6rfmsshg9hqdpqrh8dyaulzwg62x6h3qs39tqhp5vqcr4c3tnxyxr08rk28n8mkphe6c5gfusmyncpmdh604trq3cafqcqzzsxqzfvsp5un4ey9rh0pl23648xtng2k6gtw7w2p6ldaexl6ylwcuhnsnxnsfs9qyyssqxnhr6jvdqfwr97qk7dtsnqaps78r7fjlpyz5z57r2k70az5tvvss4tpucycqpph8gx0vxxr7xse442zf8wxlskln8n77qkd4kad4t5qp92lvrm").unwrap(),
482+
String::from("lnbc923720n1pj9nre4pp58zjsgd3xkyj33wv6rfmsshg9hqdpqrh8dyaulzwg62x6h3qs39tqhp5vqcr4c3tnxyxr08rk28n8mkphe6c5gfusmyncpmdh604trq3cafqcqzzsxqzfvsp5un4ey9rh0pl23648xtng2k6gtw7w2p6ldaexl6ylwcuhnsnxnsfs9qyyssqxnhr6jvdqfwr97qk7dtsnqaps78r7fjlpyz5z57r2k70az5tvvss4tpucycqpph8gx0vxxr7xse442zf8wxlskln8n77qkd4kad4t5qp92lvrm"),
498483
vec!["test2".to_string()],
499484
);
500485
labels.insert(
501-
Bolt11Invoice::from_str("lnbc923720n1pj9nr6zpp5xmvlq2u5253htn52mflh2e6gn7pk5ht0d4qyhc62fadytccxw7hqhp5l4s6qwh57a7cwr7zrcz706qx0qy4eykcpr8m8dwz08hqf362egfscqzzsxqzfvsp5pr7yjvcn4ggrf6fq090zey0yvf8nqvdh2kq7fue0s0gnm69evy6s9qyyssqjyq0fwjr22eeg08xvmz88307yqu8tqqdjpycmermks822fpqyxgshj8hvnl9mkh6srclnxx0uf4ugfq43d66ak3rrz4dqcqd23vxwpsqf7dmhm").unwrap(),
486+
String::from("lnbc923720n1pj9nr6zpp5xmvlq2u5253htn52mflh2e6gn7pk5ht0d4qyhc62fadytccxw7hqhp5l4s6qwh57a7cwr7zrcz706qx0qy4eykcpr8m8dwz08hqf362egfscqzzsxqzfvsp5pr7yjvcn4ggrf6fq090zey0yvf8nqvdh2kq7fue0s0gnm69evy6s9qyyssqjyq0fwjr22eeg08xvmz88307yqu8tqqdjpycmermks822fpqyxgshj8hvnl9mkh6srclnxx0uf4ugfq43d66ak3rrz4dqcqd23vxwpsqf7dmhm"),
502487
vec!["test3".to_string()],
503488
);
504489
labels
@@ -517,7 +502,7 @@ mod tests {
517502
"test2".to_string(),
518503
LabelItem {
519504
addresses: vec![Address::from_str("1BitcoinEaterAddressDontSendf59kuE").unwrap()],
520-
invoices: vec![Bolt11Invoice::from_str("lnbc923720n1pj9nr6zpp5xmvlq2u5253htn52mflh2e6gn7pk5ht0d4qyhc62fadytccxw7hqhp5l4s6qwh57a7cwr7zrcz706qx0qy4eykcpr8m8dwz08hqf362egfscqzzsxqzfvsp5pr7yjvcn4ggrf6fq090zey0yvf8nqvdh2kq7fue0s0gnm69evy6s9qyyssqjyq0fwjr22eeg08xvmz88307yqu8tqqdjpycmermks822fpqyxgshj8hvnl9mkh6srclnxx0uf4ugfq43d66ak3rrz4dqcqd23vxwpsqf7dmhm").unwrap()],
505+
invoices: vec![String::from("lnbc923720n1pj9nr6zpp5xmvlq2u5253htn52mflh2e6gn7pk5ht0d4qyhc62fadytccxw7hqhp5l4s6qwh57a7cwr7zrcz706qx0qy4eykcpr8m8dwz08hqf362egfscqzzsxqzfvsp5pr7yjvcn4ggrf6fq090zey0yvf8nqvdh2kq7fue0s0gnm69evy6s9qyyssqjyq0fwjr22eeg08xvmz88307yqu8tqqdjpycmermks822fpqyxgshj8hvnl9mkh6srclnxx0uf4ugfq43d66ak3rrz4dqcqd23vxwpsqf7dmhm")],
521506
..Default::default()
522507
},
523508
);
@@ -672,7 +657,7 @@ mod tests {
672657

673658
let storage = MemoryStorage::default();
674659

675-
let invoice = Bolt11Invoice::from_str(INVOICE).unwrap();
660+
let invoice = INVOICE.to_string();
676661
let labels = vec!["label1".to_string(), "label2".to_string()];
677662

678663
let result = storage.set_invoice_labels(invoice.clone(), labels.clone());
@@ -792,7 +777,7 @@ mod tests {
792777
let storage = MemoryStorage::default();
793778

794779
let address = Address::from_str(ADDRESS).unwrap();
795-
let invoice = Bolt11Invoice::from_str(INVOICE).unwrap();
780+
let invoice = INVOICE.to_string();
796781
let label = "test_label".to_string();
797782
let other_label = "other_label".to_string();
798783
let contact = create_test_contacts().iter().next().unwrap().1.to_owned();
@@ -920,7 +905,7 @@ mod tests {
920905
assert_eq!(contact.last_used, 0);
921906
let id = storage.create_new_contact(contact.clone()).unwrap();
922907

923-
let invoice = Bolt11Invoice::from_str(INVOICE).unwrap();
908+
let invoice = INVOICE.to_string();
924909

925910
storage
926911
.set_invoice_labels(invoice, vec![id.clone()])

0 commit comments

Comments
 (0)