Skip to content

Commit

Permalink
fix: Wait for outbound capacity before paying jit channel open fees
Browse files Browse the repository at this point in the history
  • Loading branch information
holzeis committed Jul 27, 2023
1 parent ffb57c2 commit d37b56f
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 28 deletions.
5 changes: 1 addition & 4 deletions crates/tests-e2e/src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ impl TestSetup {
.await
.expect("to be able to fund");

// FIXME: Waiting here on >= as this test run on the CI can't find a route when trying to
// pay immediately after claiming a received payment.
// See: https://github.com/get10101/10101/issues/883
let ln_balance = app
.rx
.wallet_info()
Expand All @@ -70,7 +67,7 @@ impl TestSetup {
.expect("have wallet_info")
.balances
.lightning
>= funded_amount
== funded_amount
);

Self { app, coordinator }
Expand Down
13 changes: 5 additions & 8 deletions crates/tests-e2e/tests/basic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use anyhow::Result;
use assertables::assert_ge;
use assertables::assert_ge_as_result;
use bitcoin::Address;
use bitcoin::Amount;
use std::str::FromStr;
Expand Down Expand Up @@ -43,11 +41,10 @@ async fn app_can_be_funded_with_lnd_faucet() -> Result<()> {

assert_eq!(app.rx.wallet_info().unwrap().balances.on_chain, 0);

// FIXME: Asserting here on >= as this test run on the CI can't find a route when trying to pay
// immediately after claiming a received payment.
// See: https://github.com/get10101/10101/issues/883
let ln_balance = app.rx.wallet_info().unwrap().balances.lightning;
tracing::info!(%funded_amount, %ln_balance, "Successfully funded app with faucet");
assert_ge!(ln_balance, funded_amount);
tracing::info!(%funded_amount, "Successfully funded app with faucet");
assert_eq!(
app.rx.wallet_info().unwrap().balances.lightning,
funded_amount
);
Ok(())
}
6 changes: 1 addition & 5 deletions crates/tests-e2e/tests/receive_payment_when_open_position.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use native::api;
use tests_e2e::fund::FUNDING_TRANSACTION_FEES;
use tests_e2e::setup;
use tests_e2e::wait_until;
use tokio::task::spawn_blocking;
Expand All @@ -26,8 +25,5 @@ async fn can_receive_payment_with_open_position() {
let ln_balance = app.rx.wallet_info().unwrap().balances.lightning;
tracing::info!(%ln_balance, %ln_balance_before, %invoice_amount, "Lightning balance increased");

// FIXME: Change this assertion when the reason why we're being charged
// transaction funding fees now is found.
// See: https://github.com/get10101/10101/issues/883
assert!(ln_balance >= ln_balance_before + invoice_amount - FUNDING_TRANSACTION_FEES);
assert_eq!(ln_balance, ln_balance_before + invoice_amount);
}
2 changes: 0 additions & 2 deletions mobile/native/src/api.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::calculations;
use crate::channel_fee::ChannelFeePaymentSubscriber;
use crate::commons::api::ChannelInfo;
use crate::commons::api::Price;
use crate::config;
Expand Down Expand Up @@ -231,7 +230,6 @@ pub fn run(
db::init_db(&app_dir, get_network())?;
let runtime = ln_dlc::get_or_create_tokio_runtime()?;
ln_dlc::run(app_dir, seed_dir, runtime)?;
event::subscribe(ChannelFeePaymentSubscriber::new());

let (_health, tx) = health::Health::new(config, runtime);

Expand Down
67 changes: 58 additions & 9 deletions mobile/native/src/channel_fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,21 @@ use anyhow::Context;
use anyhow::Result;
use bitcoin::Txid;
use lightning_invoice::Invoice;
use ln_dlc_node::node::rust_dlc_manager::subchannel::LNChannelManager;
use ln_dlc_node::node::rust_dlc_manager::ChannelId;
use ln_dlc_node::node::ChannelManager;
use serde::Deserialize;
use serde::Serialize;
use std::str::FromStr;
use std::sync::Arc;
use std::sync::Mutex;
use std::time::Duration;
use tokio::runtime::Handle;

#[derive(Clone)]
pub struct ChannelFeePaymentSubscriber {
pub open_channel_tx: Arc<Mutex<Option<EsploraTransaction>>>,
pub open_channel_tx: Arc<Mutex<Option<(ChannelId, EsploraTransaction)>>>,
pub channel_manager: Arc<ChannelManager>,
}

#[derive(Deserialize, Serialize, Debug, Clone)]
Expand Down Expand Up @@ -51,24 +55,38 @@ impl Subscriber for ChannelFeePaymentSubscriber {
}

impl ChannelFeePaymentSubscriber {
pub fn new() -> Self {
pub fn new(channel_manager: Arc<ChannelManager>) -> Self {
Self {
open_channel_tx: Arc::new(Mutex::new(None)),
channel_manager,
}
}

/// Attempts to pay the transaction fees for opening an inbound channel.
fn pay_funding_transaction_fees(&self, amount_msats: u64) -> Result<()> {
let transaction = match self.get_funding_transaction() {
Some(transaction) => transaction,
let (channel_id, transaction) = match self.get_funding_transaction() {
Some((channel_id, transaction)) => (channel_id, transaction),
None => {
tracing::debug!("No pending funding transaction found!");
return Ok(());
}
};

tracing::debug!("Trying to pay channel opening fees of {}", transaction.fee);
let funding_tx_fees_msats = (transaction.fee * 1000) as u64;

tokio::task::block_in_place(|| {
tracing::debug!(
"Waiting for outbound capacity on channel {} to pay {funding_tx_fees_msats} msats jit channel opening fee.",
hex::encode(channel_id)
);
Handle::current()
.block_on(self.wait_for_outbound_capacity(channel_id, funding_tx_fees_msats))
})?;

tracing::debug!(
"Trying to pay channel opening fees of {} sats",
transaction.fee
);
let funding_txid = transaction.txid;

if funding_tx_fees_msats > amount_msats {
Expand Down Expand Up @@ -110,15 +128,15 @@ impl ChannelFeePaymentSubscriber {
Handle::current().block_on(fetch_funding_transaction(txid))
})?;
tracing::debug!("Successfully fetched transaction fees of {} for new inbound channel with id {channel_id_as_str}", transaction.fee);
self.set_funding_transaction(transaction);
self.set_funding_transaction(channel_id, transaction);
Ok(())
}

fn set_funding_transaction(&self, transaction: EsploraTransaction) {
fn set_funding_transaction(&self, channel_id: &ChannelId, transaction: EsploraTransaction) {
*self
.open_channel_tx
.lock()
.expect("Mutex to not be poisoned") = Some(transaction);
.expect("Mutex to not be poisoned") = Some((*channel_id, transaction));
}

fn unset_funding_transaction(&self) {
Expand All @@ -128,12 +146,43 @@ impl ChannelFeePaymentSubscriber {
.expect("Mutex to not be poisoned") = None;
}

fn get_funding_transaction(&self) -> Option<EsploraTransaction> {
fn get_funding_transaction(&self) -> Option<(ChannelId, EsploraTransaction)> {
self.open_channel_tx
.lock()
.expect("Mutex to not be poisoned")
.clone()
}

async fn wait_for_outbound_capacity(
&self,
channel_id: ChannelId,
funding_tx_fees_msats: u64,
) -> Result<()> {
tokio::time::timeout(Duration::from_secs(5), async {
loop {
let channel_details = self
.channel_manager
.get_channel_details(&channel_id)
.expect("Channel details to exist");

if channel_details.outbound_capacity_msat >= funding_tx_fees_msats {
tracing::debug!(channel_details.outbound_capacity_msat, channel_id=hex::encode(channel_id),
"Channel has enough outbound capacity");
break;
} else {
tracing::debug!(channel_id = hex::encode(channel_id), outbound_capacity_msats = channel_details.outbound_capacity_msat, funding_tx_fees_msats,
"Channel does not have enough outbound capacity to pay jit channel opening fees yet. Waiting.");
tokio::time::sleep(Duration::from_millis(200)).await
}
}
})
.await
.map_err(|e| anyhow!("{e:#}"))
.context(format!(
"Timed-out waiting for channel {} to become usable",
hex::encode(channel_id)
))
}
}

async fn fetch_funding_transaction(txid: Txid) -> Result<EsploraTransaction> {
Expand Down
5 changes: 5 additions & 0 deletions mobile/native/src/ln_dlc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use self::node::WalletHistories;
use crate::api;
use crate::calculations;
use crate::channel_fee::ChannelFeePaymentSubscriber;
use crate::commons::reqwest_client;
use crate::config;
use crate::event;
Expand Down Expand Up @@ -246,6 +247,10 @@ pub fn run(data_dir: String, seed_dir: String, runtime: &Runtime) -> Result<()>
}
});

event::subscribe(ChannelFeePaymentSubscriber::new(
node.inner.channel_manager.clone(),
));

NODE.set(node);

event::publish(&EventInternal::Init("10101 is ready.".to_string()));
Expand Down

0 comments on commit d37b56f

Please sign in to comment.