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

Commit 6cb4ff5

Browse files
committed
bolt12
1 parent 57ccd46 commit 6cb4ff5

File tree

9 files changed

+281
-60
lines changed

9 files changed

+281
-60
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;
@@ -381,3 +382,26 @@ impl From<nostr::event::builder::Error> for MutinyError {
381382
Self::NostrError
382383
}
383384
}
385+
386+
impl From<Bolt12SemanticError> for MutinyError {
387+
fn from(e: Bolt12SemanticError) -> Self {
388+
match e {
389+
Bolt12SemanticError::UnsupportedChain => MutinyError::NetworkMismatch,
390+
Bolt12SemanticError::UnexpectedChain => MutinyError::NetworkMismatch,
391+
Bolt12SemanticError::MissingAmount => MutinyError::BadAmountError,
392+
Bolt12SemanticError::InvalidAmount => MutinyError::BadAmountError,
393+
Bolt12SemanticError::InsufficientAmount => MutinyError::BadAmountError,
394+
Bolt12SemanticError::UnexpectedAmount => MutinyError::BadAmountError,
395+
Bolt12SemanticError::UnsupportedCurrency => MutinyError::BadAmountError,
396+
Bolt12SemanticError::MissingSigningPubkey => MutinyError::PubkeyInvalid,
397+
Bolt12SemanticError::InvalidSigningPubkey => MutinyError::PubkeyInvalid,
398+
Bolt12SemanticError::UnexpectedSigningPubkey => MutinyError::PubkeyInvalid,
399+
Bolt12SemanticError::MissingQuantity => MutinyError::BadAmountError,
400+
Bolt12SemanticError::InvalidQuantity => MutinyError::BadAmountError,
401+
Bolt12SemanticError::UnexpectedQuantity => MutinyError::BadAmountError,
402+
Bolt12SemanticError::MissingPaths => MutinyError::RoutingFailed,
403+
Bolt12SemanticError::AlreadyExpired => MutinyError::PaymentTimeout,
404+
_ => MutinyError::LnDecodeError,
405+
}
406+
}
407+
}

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
) {
@@ -689,10 +708,12 @@ mod test {
689708

690709
let payment_info = PaymentInfo {
691710
preimage: Some(preimage),
711+
payment_hash: None,
692712
status: HTLCStatus::Succeeded,
693713
amt_msat: MillisatAmount(Some(420)),
694714
fee_paid_msat: None,
695715
bolt11: None,
716+
bolt12: None,
696717
payee_pubkey: Some(pubkey),
697718
secret: None,
698719
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
}
@@ -89,7 +88,7 @@ pub trait LabelStorage {
8988
/// Get a map of addresses to labels. This can be used to get all the labels for an address
9089
fn get_address_labels(&self) -> Result<HashMap<String, Vec<String>>, MutinyError>;
9190
/// Get a map of invoices to labels. This can be used to get all the labels for an invoice
92-
fn get_invoice_labels(&self) -> Result<HashMap<Bolt11Invoice, Vec<String>>, MutinyError>;
91+
fn get_invoice_labels(&self) -> Result<HashMap<String, Vec<String>>, MutinyError>;
9392
/// Get all the existing labels
9493
fn get_labels(&self) -> Result<HashMap<String, LabelItem>, MutinyError>;
9594
/// Get information about a label
@@ -101,11 +100,7 @@ pub trait LabelStorage {
101100
/// Set the labels for an invoice, replacing any existing labels
102101
/// If you do not want to replace any existing labels, use `get_invoice_labels` to get the existing labels,
103102
/// add the new labels, and then use `set_invoice_labels` to set the new labels
104-
fn set_invoice_labels(
105-
&self,
106-
invoice: Bolt11Invoice,
107-
labels: Vec<String>,
108-
) -> Result<(), MutinyError>;
103+
fn set_invoice_labels(&self, invoice: String, labels: Vec<String>) -> Result<(), MutinyError>;
109104
/// Get all the existing contacts
110105
fn get_contacts(&self) -> Result<HashMap<String, Contact>, MutinyError>;
111106
/// Get a contact by label, the label should be a uuid
@@ -132,9 +127,8 @@ impl<S: MutinyStorage> LabelStorage for S {
132127
Ok(res.unwrap_or_default()) // if no labels exist, return an empty map
133128
}
134129

135-
fn get_invoice_labels(&self) -> Result<HashMap<Bolt11Invoice, Vec<String>>, MutinyError> {
136-
let res: Option<HashMap<Bolt11Invoice, Vec<String>>> =
137-
self.get_data(INVOICE_LABELS_MAP_KEY)?;
130+
fn get_invoice_labels(&self) -> Result<HashMap<String, Vec<String>>, MutinyError> {
131+
let res: Option<HashMap<String, Vec<String>>> = self.get_data(INVOICE_LABELS_MAP_KEY)?;
138132
Ok(res.unwrap_or_default()) // if no labels exist, return an empty map
139133
}
140134

@@ -200,11 +194,7 @@ impl<S: MutinyStorage> LabelStorage for S {
200194
Ok(())
201195
}
202196

203-
fn set_invoice_labels(
204-
&self,
205-
invoice: Bolt11Invoice,
206-
labels: Vec<String>,
207-
) -> Result<(), MutinyError> {
197+
fn set_invoice_labels(&self, invoice: String, labels: Vec<String>) -> Result<(), MutinyError> {
208198
// update the labels map
209199
let mut invoice_labels = self.get_invoice_labels()?;
210200
invoice_labels.insert(invoice.clone(), labels.clone());
@@ -390,7 +380,7 @@ impl<S: MutinyStorage> LabelStorage for NodeManager<S> {
390380
self.storage.get_address_labels()
391381
}
392382

393-
fn get_invoice_labels(&self) -> Result<HashMap<Bolt11Invoice, Vec<String>>, MutinyError> {
383+
fn get_invoice_labels(&self) -> Result<HashMap<String, Vec<String>>, MutinyError> {
394384
self.storage.get_invoice_labels()
395385
}
396386

@@ -406,11 +396,7 @@ impl<S: MutinyStorage> LabelStorage for NodeManager<S> {
406396
self.storage.set_address_labels(address, labels)
407397
}
408398

409-
fn set_invoice_labels(
410-
&self,
411-
invoice: Bolt11Invoice,
412-
labels: Vec<String>,
413-
) -> Result<(), MutinyError> {
399+
fn set_invoice_labels(&self, invoice: String, labels: Vec<String>) -> Result<(), MutinyError> {
414400
self.storage.set_invoice_labels(invoice, labels)
415401
}
416402

@@ -452,7 +438,6 @@ mod tests {
452438
use super::*;
453439
use crate::test_utils::*;
454440
use bitcoin::Address;
455-
use lightning_invoice::Bolt11Invoice;
456441
use std::collections::HashMap;
457442
use std::str::FromStr;
458443

@@ -480,18 +465,18 @@ mod tests {
480465
labels
481466
}
482467

483-
fn create_test_invoice_labels_map() -> HashMap<Bolt11Invoice, Vec<String>> {
468+
fn create_test_invoice_labels_map() -> HashMap<String, Vec<String>> {
484469
let mut labels = HashMap::new();
485470
labels.insert(
486-
Bolt11Invoice::from_str("lnbc923720n1pj9nrefpp5pczykgk37af5388n8dzynljpkzs7sje4melqgazlwv9y3apay8jqhp5rd8saxz3juve3eejq7z5fjttxmpaq88d7l92xv34n4h3mq6kwq2qcqzzsxqzfvsp5z0jwpehkuz9f2kv96h62p8x30nku76aj8yddpcust7g8ad0tr52q9qyyssqfy622q25helv8cj8hyxqltws4rdwz0xx2hw0uh575mn7a76cp3q4jcptmtjkjs4a34dqqxn8uy70d0qlxqleezv4zp84uk30pp5q3nqq4c9gkz").unwrap(),
471+
String::from("lnbc923720n1pj9nrefpp5pczykgk37af5388n8dzynljpkzs7sje4melqgazlwv9y3apay8jqhp5rd8saxz3juve3eejq7z5fjttxmpaq88d7l92xv34n4h3mq6kwq2qcqzzsxqzfvsp5z0jwpehkuz9f2kv96h62p8x30nku76aj8yddpcust7g8ad0tr52q9qyyssqfy622q25helv8cj8hyxqltws4rdwz0xx2hw0uh575mn7a76cp3q4jcptmtjkjs4a34dqqxn8uy70d0qlxqleezv4zp84uk30pp5q3nqq4c9gkz"),
487472
vec!["test1".to_string()],
488473
);
489474
labels.insert(
490-
Bolt11Invoice::from_str("lnbc923720n1pj9nre4pp58zjsgd3xkyj33wv6rfmsshg9hqdpqrh8dyaulzwg62x6h3qs39tqhp5vqcr4c3tnxyxr08rk28n8mkphe6c5gfusmyncpmdh604trq3cafqcqzzsxqzfvsp5un4ey9rh0pl23648xtng2k6gtw7w2p6ldaexl6ylwcuhnsnxnsfs9qyyssqxnhr6jvdqfwr97qk7dtsnqaps78r7fjlpyz5z57r2k70az5tvvss4tpucycqpph8gx0vxxr7xse442zf8wxlskln8n77qkd4kad4t5qp92lvrm").unwrap(),
475+
String::from("lnbc923720n1pj9nre4pp58zjsgd3xkyj33wv6rfmsshg9hqdpqrh8dyaulzwg62x6h3qs39tqhp5vqcr4c3tnxyxr08rk28n8mkphe6c5gfusmyncpmdh604trq3cafqcqzzsxqzfvsp5un4ey9rh0pl23648xtng2k6gtw7w2p6ldaexl6ylwcuhnsnxnsfs9qyyssqxnhr6jvdqfwr97qk7dtsnqaps78r7fjlpyz5z57r2k70az5tvvss4tpucycqpph8gx0vxxr7xse442zf8wxlskln8n77qkd4kad4t5qp92lvrm"),
491476
vec!["test2".to_string()],
492477
);
493478
labels.insert(
494-
Bolt11Invoice::from_str("lnbc923720n1pj9nr6zpp5xmvlq2u5253htn52mflh2e6gn7pk5ht0d4qyhc62fadytccxw7hqhp5l4s6qwh57a7cwr7zrcz706qx0qy4eykcpr8m8dwz08hqf362egfscqzzsxqzfvsp5pr7yjvcn4ggrf6fq090zey0yvf8nqvdh2kq7fue0s0gnm69evy6s9qyyssqjyq0fwjr22eeg08xvmz88307yqu8tqqdjpycmermks822fpqyxgshj8hvnl9mkh6srclnxx0uf4ugfq43d66ak3rrz4dqcqd23vxwpsqf7dmhm").unwrap(),
479+
String::from("lnbc923720n1pj9nr6zpp5xmvlq2u5253htn52mflh2e6gn7pk5ht0d4qyhc62fadytccxw7hqhp5l4s6qwh57a7cwr7zrcz706qx0qy4eykcpr8m8dwz08hqf362egfscqzzsxqzfvsp5pr7yjvcn4ggrf6fq090zey0yvf8nqvdh2kq7fue0s0gnm69evy6s9qyyssqjyq0fwjr22eeg08xvmz88307yqu8tqqdjpycmermks822fpqyxgshj8hvnl9mkh6srclnxx0uf4ugfq43d66ak3rrz4dqcqd23vxwpsqf7dmhm"),
495480
vec!["test3".to_string()],
496481
);
497482
labels
@@ -510,7 +495,7 @@ mod tests {
510495
"test2".to_string(),
511496
LabelItem {
512497
addresses: vec![Address::from_str("1BitcoinEaterAddressDontSendf59kuE").unwrap()],
513-
invoices: vec![Bolt11Invoice::from_str("lnbc923720n1pj9nr6zpp5xmvlq2u5253htn52mflh2e6gn7pk5ht0d4qyhc62fadytccxw7hqhp5l4s6qwh57a7cwr7zrcz706qx0qy4eykcpr8m8dwz08hqf362egfscqzzsxqzfvsp5pr7yjvcn4ggrf6fq090zey0yvf8nqvdh2kq7fue0s0gnm69evy6s9qyyssqjyq0fwjr22eeg08xvmz88307yqu8tqqdjpycmermks822fpqyxgshj8hvnl9mkh6srclnxx0uf4ugfq43d66ak3rrz4dqcqd23vxwpsqf7dmhm").unwrap()],
498+
invoices: vec![String::from("lnbc923720n1pj9nr6zpp5xmvlq2u5253htn52mflh2e6gn7pk5ht0d4qyhc62fadytccxw7hqhp5l4s6qwh57a7cwr7zrcz706qx0qy4eykcpr8m8dwz08hqf362egfscqzzsxqzfvsp5pr7yjvcn4ggrf6fq090zey0yvf8nqvdh2kq7fue0s0gnm69evy6s9qyyssqjyq0fwjr22eeg08xvmz88307yqu8tqqdjpycmermks822fpqyxgshj8hvnl9mkh6srclnxx0uf4ugfq43d66ak3rrz4dqcqd23vxwpsqf7dmhm")],
514499
..Default::default()
515500
},
516501
);
@@ -665,7 +650,7 @@ mod tests {
665650

666651
let storage = MemoryStorage::default();
667652

668-
let invoice = Bolt11Invoice::from_str(INVOICE).unwrap();
653+
let invoice = INVOICE.to_string();
669654
let labels = vec!["label1".to_string(), "label2".to_string()];
670655

671656
let result = storage.set_invoice_labels(invoice.clone(), labels.clone());
@@ -785,7 +770,7 @@ mod tests {
785770
let storage = MemoryStorage::default();
786771

787772
let address = Address::from_str(ADDRESS).unwrap();
788-
let invoice = Bolt11Invoice::from_str(INVOICE).unwrap();
773+
let invoice = INVOICE.to_string();
789774
let label = "test_label".to_string();
790775
let other_label = "other_label".to_string();
791776
let contact = create_test_contacts().iter().next().unwrap().1.to_owned();
@@ -913,7 +898,7 @@ mod tests {
913898
assert_eq!(contact.last_used, 0);
914899
let id = storage.create_new_contact(contact.clone()).unwrap();
915900

916-
let invoice = Bolt11Invoice::from_str(INVOICE).unwrap();
901+
let invoice = INVOICE.to_string();
917902

918903
storage
919904
.set_invoice_labels(invoice, vec![id.clone()])

mutiny-core/src/ldkstorage.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,10 +792,12 @@ mod test {
792792

793793
let payment_info = PaymentInfo {
794794
preimage: Some(preimage),
795+
payment_hash: Some(payment_hash.0.to_hex()),
795796
status: HTLCStatus::Succeeded,
796797
amt_msat: MillisatAmount(Some(420)),
797798
fee_paid_msat: None,
798799
bolt11: None,
800+
bolt12: None,
799801
payee_pubkey: Some(pubkey),
800802
secret: None,
801803
last_update: utils::now().as_secs(),

0 commit comments

Comments
 (0)