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

Commit 7b2a660

Browse files
Refactor getting invoice by hash
1 parent b5bc51b commit 7b2a660

File tree

5 files changed

+38
-166
lines changed

5 files changed

+38
-166
lines changed

mutiny-core/src/federation.rs

Lines changed: 2 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ use crate::{
55
key::{create_root_child_key, ChildKey},
66
logging::MutinyLogger,
77
onchain::coin_type_from_network,
8-
storage::{
9-
get_payment_info, list_payment_info, persist_payment_info, MutinyStorage, VersionedValue,
10-
},
8+
storage::{list_payment_info, persist_payment_info, MutinyStorage, VersionedValue},
119
utils::sleep,
1210
HTLCStatus, MutinyInvoice, DEFAULT_PAYMENT_TIMEOUT,
1311
};
@@ -17,7 +15,6 @@ use bip39::Mnemonic;
1715
use bitcoin::secp256k1::{SecretKey, ThirtyTwoByteHash};
1816
use bitcoin::{
1917
bip32::{ChildNumber, DerivationPath, ExtendedPrivKey},
20-
hashes::sha256,
2118
secp256k1::Secp256k1,
2219
Network,
2320
};
@@ -57,9 +54,7 @@ use fedimint_wallet_client::{WalletClientInit, WalletClientModule};
5754
use futures::{select, FutureExt};
5855
use futures_util::{pin_mut, StreamExt};
5956
use hex_conservative::{DisplayHex, FromHex};
60-
use lightning::{
61-
ln::PaymentHash, log_debug, log_error, log_info, log_trace, log_warn, util::logger::Logger,
62-
};
57+
use lightning::{log_debug, log_error, log_info, log_trace, log_warn, util::logger::Logger};
6358
use lightning_invoice::Bolt11Invoice;
6459
use serde::{de::DeserializeOwned, Deserialize, Serialize};
6560
#[cfg(not(target_arch = "wasm32"))]
@@ -76,12 +71,6 @@ use std::{
7671
#[cfg(target_arch = "wasm32")]
7772
use web_time::Instant;
7873

79-
// The amount of time in milliseconds to wait for
80-
// checking the status of a fedimint payment. This
81-
// is to work around their stream status checking
82-
// when wanting just the current status.
83-
const FEDIMINT_STATUS_TIMEOUT_CHECK_MS: u64 = 30;
84-
8574
// The maximum amount of operations we try to pull
8675
// from fedimint when we need to search through
8776
// their internal list.
@@ -516,77 +505,6 @@ impl<S: MutinyStorage> FederationClient<S> {
516505
Ok(())
517506
}
518507

519-
pub async fn get_invoice_by_hash(
520-
&self,
521-
hash: &sha256::Hash,
522-
) -> Result<MutinyInvoice, MutinyError> {
523-
log_trace!(self.logger, "get_invoice_by_hash");
524-
525-
// Try to get the invoice from storage first
526-
let (invoice, inbound) = match get_payment_info(&self.storage, hash, &self.logger) {
527-
Ok(i) => i,
528-
Err(e) => {
529-
log_error!(self.logger, "could not get invoice by hash: {e}");
530-
return Err(e);
531-
}
532-
};
533-
534-
log_trace!(self.logger, "retrieved invoice by hash");
535-
536-
if matches!(invoice.status, HTLCStatus::InFlight | HTLCStatus::Pending) {
537-
log_trace!(self.logger, "invoice still in flight, getting operations");
538-
// If the invoice is InFlight or Pending, check the operation log for updates
539-
let lightning_module = Arc::new(
540-
self.fedimint_client
541-
.get_first_module::<LightningClientModule>(),
542-
);
543-
544-
let operations = self
545-
.fedimint_client
546-
.operation_log()
547-
.list_operations(FEDIMINT_OPERATIONS_LIST_MAX, None)
548-
.await;
549-
550-
log_trace!(
551-
self.logger,
552-
"going to go through {} operations",
553-
operations.len()
554-
);
555-
for (key, entry) in operations {
556-
if entry.operation_module_kind() == LightningCommonInit::KIND.as_str() {
557-
if let Some(updated_invoice) = process_operation_until_timeout(
558-
self.logger.clone(),
559-
entry.meta(),
560-
hash.into_32(),
561-
key.operation_id,
562-
&lightning_module,
563-
Some(FEDIMINT_STATUS_TIMEOUT_CHECK_MS),
564-
self.stop.clone(),
565-
)
566-
.await
567-
{
568-
self.maybe_update_after_checking_fedimint(updated_invoice.clone())?;
569-
return Ok(updated_invoice);
570-
}
571-
} else {
572-
log_warn!(
573-
self.logger,
574-
"Unsupported module: {}",
575-
entry.operation_module_kind()
576-
);
577-
}
578-
}
579-
} else {
580-
// If the invoice is not InFlight or Pending, return it directly
581-
log_trace!(self.logger, "returning final invoice");
582-
// TODO labels
583-
return MutinyInvoice::from(invoice, PaymentHash(hash.into_32()), inbound, vec![]);
584-
}
585-
586-
log_debug!(self.logger, "could not find invoice");
587-
Err(MutinyError::NotFound)
588-
}
589-
590508
pub(crate) async fn pay_invoice(
591509
&self,
592510
invoice: Bolt11Invoice,

mutiny-core/src/lib.rs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ mod test_utils;
4646
pub use crate::gossip::{GOSSIP_SYNC_TIME_KEY, NETWORK_GRAPH_KEY, PROB_SCORER_KEY};
4747
pub use crate::keymanager::generate_seed;
4848
pub use crate::ldkstorage::{CHANNEL_CLOSURE_PREFIX, CHANNEL_MANAGER_KEY, MONITORS_PREFIX_KEY};
49-
use crate::nostr::primal::{PrimalApi, PrimalClient};
5049
use crate::storage::{
5150
get_payment_hash_from_key, list_payment_info, persist_payment_info, update_nostr_contact_list,
5251
IndexItem, MutinyStorage, DEVICE_ID_KEY, EXPECTED_NETWORK_KEY, NEED_FULL_SYNC_KEY,
@@ -79,6 +78,10 @@ use crate::{
7978
nostr::nwc::{BudgetPeriod, BudgetedSpendingConditions, NwcProfileTag, SpendingConditions},
8079
subscription::MutinySubscriptionClient,
8180
};
81+
use crate::{
82+
nostr::primal::{PrimalApi, PrimalClient},
83+
storage::get_invoice_by_hash,
84+
};
8285
use crate::{nostr::NostrManager, utils::sleep};
8386
use ::nostr::nips::nip47::Method;
8487
use ::nostr::nips::nip57;
@@ -1968,20 +1971,7 @@ impl<S: MutinyStorage> MutinyWallet<S> {
19681971
&self,
19691972
hash: &sha256::Hash,
19701973
) -> Result<MutinyInvoice, MutinyError> {
1971-
// First, try to find the invoice in the node manager
1972-
if let Ok(invoice) = self.node_manager.get_invoice_by_hash(hash).await {
1973-
return Ok(invoice);
1974-
}
1975-
1976-
// If not found in node manager, search in federations
1977-
let federations = self.federations.read().await;
1978-
for (_fed_id, federation) in federations.iter() {
1979-
if let Ok(invoice) = federation.get_invoice_by_hash(hash).await {
1980-
return Ok(invoice);
1981-
}
1982-
}
1983-
1984-
Err(MutinyError::NotFound)
1974+
get_invoice_by_hash(hash, &self.storage, &self.logger)
19851975
}
19861976

19871977
/// Checks whether or not the user is subscribed to Mutiny+.

mutiny-core/src/node.rs

Lines changed: 13 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,23 +1336,6 @@ impl<S: MutinyStorage> Node<S> {
13361336
Ok(())
13371337
}
13381338

1339-
pub fn get_invoice_by_hash(&self, payment_hash: &Sha256) -> Result<MutinyInvoice, MutinyError> {
1340-
let (payment_info, inbound) = self.get_payment_info_from_persisters(payment_hash)?;
1341-
let labels_map = self.persister.storage.get_invoice_labels()?;
1342-
let labels = payment_info
1343-
.bolt11
1344-
.as_ref()
1345-
.and_then(|inv| labels_map.get(inv).cloned())
1346-
.unwrap_or_default();
1347-
1348-
MutinyInvoice::from(
1349-
payment_info,
1350-
PaymentHash(payment_hash.into_32()),
1351-
inbound,
1352-
labels,
1353-
)
1354-
}
1355-
13561339
/// Gets all the closed channels for this node
13571340
pub fn get_channel_closure(
13581341
&self,
@@ -1366,32 +1349,6 @@ impl<S: MutinyStorage> Node<S> {
13661349
self.persister.list_channel_closures()
13671350
}
13681351

1369-
pub fn get_payment_info_from_persisters(
1370-
&self,
1371-
payment_hash: &bitcoin::hashes::sha256::Hash,
1372-
) -> Result<(PaymentInfo, bool), MutinyError> {
1373-
// try inbound first
1374-
if let Some(payment_info) = read_payment_info(
1375-
&self.persister.storage,
1376-
&payment_hash.into_32(),
1377-
true,
1378-
&self.logger,
1379-
) {
1380-
return Ok((payment_info, true));
1381-
}
1382-
1383-
// if no inbound check outbound
1384-
match read_payment_info(
1385-
&self.persister.storage,
1386-
&payment_hash.into_32(),
1387-
false,
1388-
&self.logger,
1389-
) {
1390-
Some(payment_info) => Ok((payment_info, false)),
1391-
None => Err(MutinyError::NotFound),
1392-
}
1393-
}
1394-
13951352
fn retry_strategy() -> Retry {
13961353
Retry::Attempts(15)
13971354
}
@@ -2431,6 +2388,7 @@ pub(crate) fn default_user_config(accept_underpaying_htlcs: bool) -> UserConfig
24312388
#[cfg(not(target_arch = "wasm32"))]
24322389
mod tests {
24332390
use super::*;
2391+
use crate::get_invoice_by_hash;
24342392
use crate::node::{map_sending_failure, parse_peer_info};
24352393
use crate::storage::MemoryStorage;
24362394
use crate::test_utils::*;
@@ -2589,6 +2547,7 @@ mod tests {
25892547
async fn test_create_invoice() {
25902548
let storage = MemoryStorage::default();
25912549
let node = create_node(storage.clone()).await;
2550+
let logger = Arc::new(MutinyLogger::default());
25922551

25932552
let now = crate::utils::now().as_secs();
25942553

@@ -2607,8 +2566,8 @@ mod tests {
26072566
_ => panic!("unexpected invoice description"),
26082567
}
26092568

2610-
let from_storage = node.get_invoice_by_hash(invoice.payment_hash()).unwrap();
2611-
let by_hash = node.get_invoice_by_hash(invoice.payment_hash()).unwrap();
2569+
let from_storage = get_invoice_by_hash(invoice.payment_hash(), &storage, &logger).unwrap();
2570+
let by_hash = get_invoice_by_hash(invoice.payment_hash(), &storage, &logger).unwrap();
26122571

26132572
assert_eq!(from_storage, by_hash);
26142573
assert_eq!(from_storage.bolt11, Some(invoice.clone()));
@@ -2723,16 +2682,20 @@ mod tests {
27232682
#[cfg(test)]
27242683
#[cfg(target_arch = "wasm32")]
27252684
mod wasm_test {
2726-
use crate::event::{MillisatAmount, PaymentInfo};
2727-
use crate::labels::LabelStorage;
27282685
use crate::storage::MemoryStorage;
27292686
use crate::test_utils::create_node;
27302687
use crate::{error::MutinyError, storage::persist_payment_info};
2688+
use crate::{
2689+
event::{MillisatAmount, PaymentInfo},
2690+
storage::get_invoice_by_hash,
2691+
};
2692+
use crate::{labels::LabelStorage, logging::MutinyLogger};
27312693
use crate::{HTLCStatus, PrivacyLevel};
27322694
use itertools::Itertools;
27332695
use lightning::ln::channelmanager::PaymentId;
27342696
use lightning::ln::PaymentHash;
27352697
use lightning_invoice::Bolt11InvoiceDescription;
2698+
use std::sync::Arc;
27362699
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
27372700

27382701
wasm_bindgen_test_configure!(run_in_browser);
@@ -2748,6 +2711,7 @@ mod wasm_test {
27482711
async fn test_create_invoice() {
27492712
let storage = MemoryStorage::default();
27502713
let node = create_node(storage.clone()).await;
2714+
let logger = Arc::new(MutinyLogger::default());
27512715

27522716
let now = crate::utils::now().as_secs();
27532717

@@ -2768,8 +2732,8 @@ mod wasm_test {
27682732
_ => panic!("unexpected invoice description"),
27692733
}
27702734

2771-
let from_storage = node.get_invoice_by_hash(invoice.payment_hash()).unwrap();
2772-
let by_hash = node.get_invoice_by_hash(invoice.payment_hash()).unwrap();
2735+
let from_storage = get_invoice_by_hash(invoice.payment_hash(), &storage, &logger).unwrap();
2736+
let by_hash = get_invoice_by_hash(invoice.payment_hash(), &storage, &logger).unwrap();
27732737

27742738
assert_eq!(from_storage, by_hash);
27752739
assert_eq!(from_storage.bolt11, Some(invoice.clone()));

mutiny-core/src/nodemanager.rs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ use bitcoin::address::NetworkUnchecked;
3131
use bitcoin::bip32::ExtendedPrivKey;
3232
use bitcoin::blockdata::script;
3333
use bitcoin::hashes::hex::FromHex;
34-
use bitcoin::hashes::sha256;
3534
use bitcoin::psbt::PartiallySignedTransaction;
3635
use bitcoin::secp256k1::PublicKey;
3736
use bitcoin::{Address, Network, OutPoint, Transaction, Txid};
@@ -1415,22 +1414,6 @@ impl<S: MutinyStorage> NodeManager<S> {
14151414
.await
14161415
}
14171416

1418-
/// Gets an invoice from the node manager.
1419-
/// This includes sent and received invoices.
1420-
pub(crate) async fn get_invoice_by_hash(
1421-
&self,
1422-
hash: &sha256::Hash,
1423-
) -> Result<MutinyInvoice, MutinyError> {
1424-
let nodes = self.nodes.read().await;
1425-
for (_, node) in nodes.iter() {
1426-
if let Ok(inv) = node.get_invoice_by_hash(hash) {
1427-
return Ok(inv);
1428-
}
1429-
}
1430-
1431-
Err(MutinyError::NotFound)
1432-
}
1433-
14341417
pub async fn get_channel_closure(
14351418
&self,
14361419
user_channel_id: u128,

mutiny-core/src/storage.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::event::HTLCStatus;
1+
use crate::labels::LabelStorage;
22
use crate::nodemanager::{ChannelClosure, NodeStorage};
33
use crate::utils::{now, spawn};
44
use crate::vss::{MutinyVssClient, VssKeyValueItem};
@@ -12,6 +12,7 @@ use crate::{
1212
error::{MutinyError, MutinyStorageError},
1313
event::PaymentInfo,
1414
};
15+
use crate::{event::HTLCStatus, MutinyInvoice};
1516
use crate::{ldkstorage::CHANNEL_MANAGER_KEY, utils::sleep};
1617
use async_trait::async_trait;
1718
use bdk::chain::{Append, PersistBackend};
@@ -934,6 +935,22 @@ pub(crate) fn persist_payment_info<S: MutinyStorage>(
934935
Ok(())
935936
}
936937

938+
pub(crate) fn get_invoice_by_hash<S: MutinyStorage>(
939+
hash: &bitcoin::hashes::sha256::Hash,
940+
storage: &S,
941+
logger: &MutinyLogger,
942+
) -> Result<MutinyInvoice, MutinyError> {
943+
let (payment_info, inbound) = get_payment_info(storage, hash, logger)?;
944+
let labels_map = storage.get_invoice_labels()?;
945+
let labels = payment_info
946+
.bolt11
947+
.as_ref()
948+
.and_then(|inv| labels_map.get(inv).cloned())
949+
.unwrap_or_default();
950+
951+
MutinyInvoice::from(payment_info, PaymentHash(hash.into_32()), inbound, labels)
952+
}
953+
937954
pub(crate) fn get_payment_info<S: MutinyStorage>(
938955
storage: &S,
939956
payment_hash: &bitcoin::hashes::sha256::Hash,

0 commit comments

Comments
 (0)