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

Commit 34a490a

Browse files
committed
Persist payjoin sessions
1 parent c0b756a commit 34a490a

3 files changed

Lines changed: 66 additions & 3 deletions

File tree

mutiny-core/src/lib.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
type_alias_bounds
99
)]
1010
extern crate core;
11+
extern crate payjoin as pj;
1112

1213
pub mod auth;
1314
mod chain;
@@ -30,6 +31,7 @@ mod node;
3031
pub mod nodemanager;
3132
pub mod nostr;
3233
mod onchain;
34+
mod payjoin;
3335
mod peermanager;
3436
pub mod redshift;
3537
pub mod scorer;
@@ -55,6 +57,7 @@ use crate::nostr::nwc::{
5557
BudgetPeriod, BudgetedSpendingConditions, NwcProfileTag, SpendingConditions,
5658
};
5759
use crate::nostr::MUTINY_PLUS_SUBSCRIPTION_LABEL;
60+
use crate::payjoin::PayjoinStorage;
5861
use crate::storage::{MutinyStorage, DEVICE_ID_KEY, EXPECTED_NETWORK_KEY, NEED_FULL_SYNC_KEY};
5962
use crate::{auth::MutinyAuthClient, logging::MutinyLogger};
6063
use crate::{error::MutinyError, nostr::ReservedProfile};
@@ -431,6 +434,7 @@ impl<S: MutinyStorage> MutinyWallet<S> {
431434
.await?,
432435
);
433436
NodeManager::start_sync(self.node_manager.clone());
437+
NodeManager::resume_payjoins(self.node_manager.clone());
434438

435439
// Redshifts disabled in safe mode
436440
if !self.config.safe_mode {
@@ -691,7 +695,7 @@ impl<S: MutinyStorage> MutinyWallet<S> {
691695
.await
692696
.unwrap();
693697

694-
let mut enroller = payjoin::receive::v2::Enroller::from_relay_config(
698+
let mut enroller = pj::receive::v2::Enroller::from_relay_config(
695699
PAYJOIN_DIR,
696700
&ohttp_config_base64,
697701
OHTTP_RELAYS[0], // TODO pick ohttp relay at random
@@ -710,13 +714,19 @@ impl<S: MutinyStorage> MutinyWallet<S> {
710714
.process_res(ohttp_response.as_ref(), context)
711715
.map_err(|e| anyhow!("parse error {}", e))
712716
.unwrap();
717+
self.node_manager
718+
.storage
719+
.persist_payjoin(enrolled.clone())
720+
.unwrap();
713721
let pj_uri = enrolled.fallback_target();
714722
log_debug!(self.logger, "{pj_uri}");
715723
let wallet = self.node_manager.wallet.clone();
716724
let stop = self.node_manager.stop.clone();
717725
// run await payjoin task in the background as it'll keep polling the relay
718726
utils::spawn(async move {
719-
let pj_txid = NodeManager::receive_payjoin(wallet, stop, enrolled).await.unwrap();
727+
let pj_txid = NodeManager::receive_payjoin(wallet, stop, enrolled)
728+
.await
729+
.unwrap();
720730
log::info!("Received payjoin txid: {}", pj_txid);
721731
});
722732
Some(pj_uri)
@@ -727,7 +737,7 @@ impl<S: MutinyStorage> MutinyWallet<S> {
727737
invoice,
728738
btc_amount: amount.map(|amount| bitcoin::Amount::from_sat(amount).to_btc().to_string()),
729739
labels,
730-
pj
740+
pj,
731741
})
732742
}
733743

mutiny-core/src/nodemanager.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::logging::LOGGING_KEY;
2+
use crate::payjoin::PayjoinStorage;
23
use crate::redshift::{RedshiftManager, RedshiftStatus, RedshiftStorage};
34
use crate::storage::{MutinyStorage, DEVICE_ID_KEY, KEYCHAIN_STORE_KEY, NEED_FULL_SYNC_KEY};
45
use crate::utils::{sleep, spawn};
@@ -704,6 +705,19 @@ impl<S: MutinyStorage> NodeManager<S> {
704705
Ok(())
705706
}
706707

708+
/// Starts a background task to poll payjoin sessions to attempt receiving.
709+
pub(crate) fn resume_payjoins(nm: Arc<NodeManager<S>>) {
710+
let all = nm.storage.get_payjoins().unwrap_or_default();
711+
for payjoin in all {
712+
let wallet = nm.wallet.clone();
713+
let stop = nm.stop.clone();
714+
utils::spawn(async move {
715+
let pj_txid = Self::receive_payjoin(wallet, stop, payjoin).await.unwrap();
716+
log::info!("Received payjoin txid: {}", pj_txid);
717+
});
718+
}
719+
}
720+
707721
/// Starts a background tasks to poll redshifts until they are ready and then start attempting payments.
708722
///
709723
/// This function will first find redshifts that are in the [RedshiftStatus::AttemptingPayments] state and start attempting payments

mutiny-core/src/payjoin.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use crate::error::MutinyError;
2+
use crate::storage::MutinyStorage;
3+
use bitcoin::hashes::hex::ToHex;
4+
use payjoin::receive::v2::Enrolled;
5+
use std::collections::HashMap;
6+
7+
// #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8+
// pub struct Session {
9+
// pub id: [u8; 16],
10+
// pub enrolled: Enrolled,
11+
// }
12+
13+
pub trait PayjoinStorage {
14+
fn get_payjoin(&self, id: &[u8; 33]) -> Result<Option<Enrolled>, MutinyError>;
15+
fn get_payjoins(&self) -> Result<Vec<Enrolled>, MutinyError>;
16+
fn persist_payjoin(&self, session: Enrolled) -> Result<(), MutinyError>;
17+
}
18+
19+
const PAYJOIN_KEY_PREFIX: &str = "payjoin/";
20+
21+
fn get_payjoin_key(id: &[u8; 33]) -> String {
22+
format!("{PAYJOIN_KEY_PREFIX}{}", id.to_hex())
23+
}
24+
25+
impl<S: MutinyStorage> PayjoinStorage for S {
26+
fn get_payjoin(&self, id: &[u8; 33]) -> Result<Option<Enrolled>, MutinyError> {
27+
let sessions = self.get_data(get_payjoin_key(id))?;
28+
Ok(sessions)
29+
}
30+
31+
fn get_payjoins(&self) -> Result<Vec<Enrolled>, MutinyError> {
32+
let map: HashMap<String, Enrolled> = self.scan(PAYJOIN_KEY_PREFIX, None)?;
33+
Ok(map.values().map(|v| v.to_owned()).collect())
34+
}
35+
36+
fn persist_payjoin(&self, session: Enrolled) -> Result<(), MutinyError> {
37+
self.set_data(get_payjoin_key(&session.pubkey()), session, None)
38+
}
39+
}

0 commit comments

Comments
 (0)