diff --git a/coordinator/src/admin.rs b/coordinator/src/admin.rs index f35452091..7e359da94 100644 --- a/coordinator/src/admin.rs +++ b/coordinator/src/admin.rs @@ -291,6 +291,7 @@ pub async fn send_payment( .node .inner .pay_invoice(&invoice, None) + .await .map_err(|e| AppError::InternalServerError(format!("{e:#}")))?; Ok(()) diff --git a/crates/ln-dlc-node/src/node/invoice.rs b/crates/ln-dlc-node/src/node/invoice.rs index 9f1379856..ec8daf30b 100644 --- a/crates/ln-dlc-node/src/node/invoice.rs +++ b/crates/ln-dlc-node/src/node/invoice.rs @@ -35,8 +35,9 @@ use std::fmt::Formatter; use std::time::Duration; use std::time::SystemTime; use time::OffsetDateTime; +use tokio::task::spawn_blocking; -impl Node { +impl Node { pub fn create_invoice( &self, amount_in_sats: u64, @@ -221,21 +222,33 @@ impl Node { Ok(route_hint_hop) } - pub fn pay_invoice(&self, invoice: &Bolt11Invoice, amount: Option) -> Result<()> { + pub async fn pay_invoice(&self, invoice: &Bolt11Invoice, amount: Option) -> Result<()> { let (result, amt_msat) = match invoice.amount_milli_satoshis() { Some(_) => { - let result = pay_invoice(invoice, Retry::Attempts(10), &self.channel_manager); + let result = spawn_blocking({ + let invoice = invoice.clone(); + let channel_manager = self.channel_manager.clone(); + move || pay_invoice(&invoice, Retry::Attempts(10), &channel_manager) + }) + .await?; (result, invoice.amount_milli_satoshis().expect("to be set")) } None => { let amount_msats = amount.context("Can't pay zero amount invoice without amount")? * 1000; - let result = pay_zero_value_invoice( - invoice, - amount_msats, - Retry::Attempts(10), - &self.channel_manager, - ); + let result = spawn_blocking({ + let invoice = invoice.clone(); + let channel_manager = self.channel_manager.clone(); + move || { + pay_zero_value_invoice( + &invoice, + amount_msats, + Retry::Attempts(10), + &channel_manager, + ) + } + }) + .await?; (result, amount_msats) } }; diff --git a/crates/ln-dlc-node/src/tests/just_in_time_channel/create.rs b/crates/ln-dlc-node/src/tests/just_in_time_channel/create.rs index b05ba6e43..4be88e99b 100644 --- a/crates/ln-dlc-node/src/tests/just_in_time_channel/create.rs +++ b/crates/ln-dlc-node/src/tests/just_in_time_channel/create.rs @@ -153,7 +153,7 @@ async fn fail_to_open_jit_channel_with_fee_rate_over_max() { ) .unwrap(); - payer.pay_invoice(&invoice, None).unwrap(); + payer.pay_invoice(&invoice, None).await.unwrap(); // Assert @@ -208,7 +208,7 @@ async fn open_jit_channel_with_disconnected_payee() { ) .unwrap(); - payer.pay_invoice(&invoice, None).unwrap(); + payer.pay_invoice(&invoice, None).await.unwrap(); // We wait a little bit until reconnecting to simulate a pending JIT channel on the coordinator tokio::time::sleep(Duration::from_secs(5)).await; @@ -308,7 +308,7 @@ pub(crate) async fn send_interceptable_payment( "Invoice amount larger than maximum inbound HTLC in payer-coordinator channel" ); - payer.pay_invoice(&invoice, None)?; + payer.pay_invoice(&invoice, None).await?; payee .wait_for_payment_claimed(invoice.payment_hash()) @@ -391,7 +391,7 @@ pub(crate) async fn send_payment( "Invoice amount larger than maximum inbound HTLC in payer-coordinator channel" ); - payer.pay_invoice(&invoice, None)?; + payer.pay_invoice(&invoice, None).await?; payee .wait_for_payment_claimed(invoice.payment_hash()) diff --git a/crates/ln-dlc-node/src/tests/just_in_time_channel/fail_intercepted_htlc.rs b/crates/ln-dlc-node/src/tests/just_in_time_channel/fail_intercepted_htlc.rs index b9bb2cc1f..b0ea05db3 100644 --- a/crates/ln-dlc-node/src/tests/just_in_time_channel/fail_intercepted_htlc.rs +++ b/crates/ln-dlc-node/src/tests/just_in_time_channel/fail_intercepted_htlc.rs @@ -58,7 +58,7 @@ async fn fail_intercepted_htlc_if_coordinator_cannot_reconnect_to_payee() { payee.disconnect(coordinator.info); tokio::time::sleep(Duration::from_secs(1)).await; - payer.pay_invoice(&invoice, None).unwrap(); + payer.pay_invoice(&invoice, None).await.unwrap(); // Assert @@ -128,7 +128,7 @@ async fn fail_intercepted_htlc_if_connection_lost_after_funding_tx_generated() { // Act - payer.pay_invoice(&invoice, None).unwrap(); + payer.pay_invoice(&invoice, None).await.unwrap(); tokio::time::timeout(Duration::from_secs(30), async { loop { @@ -204,7 +204,7 @@ async fn fail_intercepted_htlc_if_coordinator_cannot_pay_to_open_jit_channel() { ) .unwrap(); - payer.pay_invoice(&invoice, None).unwrap(); + payer.pay_invoice(&invoice, None).await.unwrap(); // Assert diff --git a/crates/ln-dlc-node/src/tests/multi_hop_payment.rs b/crates/ln-dlc-node/src/tests/multi_hop_payment.rs index 73b9293c3..30d29601c 100644 --- a/crates/ln-dlc-node/src/tests/multi_hop_payment.rs +++ b/crates/ln-dlc-node/src/tests/multi_hop_payment.rs @@ -64,7 +64,7 @@ async fn multi_hop_payment() { invoice_amount_sat, ); - payer.pay_invoice(&invoice, None).unwrap(); + payer.pay_invoice(&invoice, None).await.unwrap(); payee .wait_for_payment_claimed(invoice.payment_hash()) diff --git a/crates/ln-dlc-node/src/tests/single_hop_payment.rs b/crates/ln-dlc-node/src/tests/single_hop_payment.rs index 3251c7387..076cf9150 100644 --- a/crates/ln-dlc-node/src/tests/single_hop_payment.rs +++ b/crates/ln-dlc-node/src/tests/single_hop_payment.rs @@ -36,7 +36,7 @@ async fn single_hop_payment() { .create_invoice(invoice_amount, "".to_string(), 180) .unwrap(); - payer.pay_invoice(&invoice, None).unwrap(); + payer.pay_invoice(&invoice, None).await.unwrap(); payee .wait_for_payment_claimed(invoice.payment_hash()) diff --git a/maker/src/routes.rs b/maker/src/routes.rs index acb401e3a..39e43cc07 100644 --- a/maker/src/routes.rs +++ b/maker/src/routes.rs @@ -256,6 +256,7 @@ pub async fn pay_invoice( state .node .pay_invoice(&invoice, None) + .await .map_err(|e| AppError::InternalServerError(format!("Could not pay invoice {e:#}")))?; Ok(()) } diff --git a/mobile/native/src/api.rs b/mobile/native/src/api.rs index e8b73e215..8a55712a5 100644 --- a/mobile/native/src/api.rs +++ b/mobile/native/src/api.rs @@ -403,7 +403,8 @@ pub enum SendPayment { } pub fn send_payment(payment: SendPayment) -> Result<()> { - ln_dlc::send_payment(payment) + let runtime = ln_dlc::get_or_create_tokio_runtime()?; + runtime.block_on(async { ln_dlc::send_payment(payment).await }) } pub struct LastLogin { diff --git a/mobile/native/src/ln_dlc/mod.rs b/mobile/native/src/ln_dlc/mod.rs index 789674eef..09ca57479 100644 --- a/mobile/native/src/ln_dlc/mod.rs +++ b/mobile/native/src/ln_dlc/mod.rs @@ -1006,13 +1006,14 @@ pub fn create_invoice(amount_sats: Option) -> Result { ) } -pub fn send_payment(payment: SendPayment) -> Result<()> { +pub async fn send_payment(payment: SendPayment) -> Result<()> { match payment { SendPayment::Lightning { invoice, amount } => { let invoice = Bolt11Invoice::from_str(&invoice)?; crate::state::get_node() .inner - .pay_invoice(&invoice, amount)?; + .pay_invoice(&invoice, amount) + .await?; } SendPayment::OnChain { address, amount } => { let address = Address::from_str(&address)?;