|
1 | 1 | use crate::event::{HTLCStatus, PaymentInfo}; |
2 | 2 | use crate::labels::LabelStorage; |
3 | 3 | use crate::logging::LOGGING_KEY; |
4 | | -use crate::payjoin::PayjoinStorage; |
| 4 | +use crate::payjoin::{Error as PayjoinError, PayjoinStorage}; |
5 | 5 | use crate::utils::{sleep, spawn}; |
6 | 6 | use crate::ActivityItem; |
7 | 7 | use crate::MutinyWalletConfig; |
@@ -47,6 +47,7 @@ use lightning::util::logger::*; |
47 | 47 | use lightning::{log_debug, log_error, log_info, log_warn}; |
48 | 48 | use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription}; |
49 | 49 | use lightning_transaction_sync::EsploraSyncClient; |
| 50 | +use payjoin::receive::v2::Enrolled; |
50 | 51 | use payjoin::Uri; |
51 | 52 | use reqwest::Client; |
52 | 53 | use serde::{Deserialize, Serialize}; |
@@ -693,15 +694,7 @@ impl<S: MutinyStorage> NodeManager<S> { |
693 | 694 | pub(crate) fn resume_payjoins(nm: Arc<NodeManager<S>>) { |
694 | 695 | let all = nm.storage.get_payjoins().unwrap_or_default(); |
695 | 696 | for payjoin in all { |
696 | | - let wallet = nm.wallet.clone(); |
697 | | - let stop = nm.stop.clone(); |
698 | | - let storage = Arc::new(nm.storage.clone()); |
699 | | - utils::spawn(async move { |
700 | | - let pj_txid = Self::receive_payjoin(wallet, stop, storage, payjoin) |
701 | | - .await |
702 | | - .unwrap(); |
703 | | - log::info!("Received payjoin txid: {}", pj_txid); |
704 | | - }); |
| 697 | + nm.clone().spawn_payjoin_receiver(payjoin); |
705 | 698 | } |
706 | 699 | } |
707 | 700 |
|
@@ -793,6 +786,31 @@ impl<S: MutinyStorage> NodeManager<S> { |
793 | 786 | Err(MutinyError::WalletOperationFailed) |
794 | 787 | } |
795 | 788 |
|
| 789 | + pub async fn start_payjoin_session(&self) -> Result<Enrolled, PayjoinError> { |
| 790 | + // DANGER! TODO get from &self config, do not get config directly from PAYJOIN_DIR ohttp-gateway |
| 791 | + // That would reveal IP address |
| 792 | + |
| 793 | + let http_client = reqwest::Client::builder().build()?; |
| 794 | + |
| 795 | + let ohttp_config_base64 = http_client |
| 796 | + .get(format!("{}/ohttp-config", crate::payjoin::PAYJOIN_DIR)) |
| 797 | + .send() |
| 798 | + .await? |
| 799 | + .text() |
| 800 | + .await?; |
| 801 | + |
| 802 | + let mut enroller = payjoin::receive::v2::Enroller::from_relay_config( |
| 803 | + crate::payjoin::PAYJOIN_DIR, |
| 804 | + &ohttp_config_base64, |
| 805 | + crate::payjoin::OHTTP_RELAYS[0], // TODO pick ohttp relay at random |
| 806 | + ); |
| 807 | + // enroll client |
| 808 | + let (req, context) = enroller.extract_req()?; |
| 809 | + let ohttp_response = http_client.post(req.url).body(req.body).send().await?; |
| 810 | + let ohttp_response = ohttp_response.bytes().await?; |
| 811 | + Ok(enroller.process_res(ohttp_response.as_ref(), context)?) |
| 812 | + } |
| 813 | + |
796 | 814 | // Send v1 payjoin request |
797 | 815 | pub async fn send_payjoin( |
798 | 816 | &self, |
@@ -865,38 +883,45 @@ impl<S: MutinyStorage> NodeManager<S> { |
865 | 883 | Ok(txid) |
866 | 884 | } |
867 | 885 |
|
| 886 | + pub fn spawn_payjoin_receiver(&self, session: crate::payjoin::Session) { |
| 887 | + let logger = self.logger.clone(); |
| 888 | + let wallet = self.wallet.clone(); |
| 889 | + let stop = self.stop.clone(); |
| 890 | + let storage = Arc::new(self.storage.clone()); |
| 891 | + utils::spawn(async move { |
| 892 | + match Self::receive_payjoin(wallet, stop, storage, session).await { |
| 893 | + Ok(txid) => log_info!(logger, "Received payjoin txid: {txid}"), |
| 894 | + Err(e) => log_error!(logger, "Error receiving payjoin: {e}"), |
| 895 | + }; |
| 896 | + }); |
| 897 | + } |
| 898 | + |
868 | 899 | /// Poll the payjoin relay to maintain a payjoin session and create a payjoin proposal. |
869 | | - pub async fn receive_payjoin( |
| 900 | + async fn receive_payjoin( |
870 | 901 | wallet: Arc<OnChainWallet<S>>, |
871 | 902 | stop: Arc<AtomicBool>, |
872 | 903 | storage: Arc<S>, |
873 | 904 | mut session: crate::payjoin::Session, |
874 | | - ) -> Result<Txid, MutinyError> { |
| 905 | + ) -> Result<Txid, PayjoinError> { |
875 | 906 | let http_client = reqwest::Client::builder() |
876 | 907 | //.danger_accept_invalid_certs(true) ? is tls unchecked :O |
877 | | - .build() |
878 | | - .unwrap(); |
| 908 | + .build()?; |
879 | 909 | let proposal: payjoin::receive::v2::UncheckedProposal = |
880 | 910 | Self::poll_for_fallback_psbt(stop, storage, &http_client, &mut session) |
881 | 911 | .await |
882 | 912 | .unwrap(); |
883 | | - let payjoin_proposal = wallet.process_payjoin_proposal(proposal).unwrap(); |
| 913 | + let payjoin_proposal = wallet |
| 914 | + .process_payjoin_proposal(proposal) |
| 915 | + .map_err(PayjoinError::Wallet)?; |
884 | 916 |
|
885 | | - let (req, ohttp_ctx) = payjoin_proposal.extract_v2_req().unwrap(); // extraction failed |
886 | | - let res = http_client |
887 | | - .post(req.url) |
888 | | - .body(req.body) |
889 | | - .send() |
890 | | - .await |
891 | | - .unwrap(); |
892 | | - let res = res.bytes().await.unwrap(); |
| 917 | + let (req, ohttp_ctx) = payjoin_proposal.extract_v2_req()?; // extraction failed |
| 918 | + let res = http_client.post(req.url).body(req.body).send().await?; |
| 919 | + let res = res.bytes().await?; |
893 | 920 | // enroll must succeed |
894 | | - let _res = payjoin_proposal |
895 | | - .deserialize_res(res.to_vec(), ohttp_ctx) |
896 | | - .unwrap(); |
| 921 | + let _res = payjoin_proposal.deserialize_res(res.to_vec(), ohttp_ctx)?; |
897 | 922 | // convert from bitcoin 29 to 30 |
898 | 923 | let txid = payjoin_proposal.psbt().clone().extract_tx().txid(); |
899 | | - let txid = Txid::from_str(&txid.to_string()).unwrap(); |
| 924 | + let txid = Txid::from_str(&txid.to_string()).map_err(PayjoinError::Txid)?; |
900 | 925 | Ok(txid) |
901 | 926 | } |
902 | 927 |
|
|
0 commit comments