Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 52 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,13 @@ pub(crate) fn default_user_config(config: &Config) -> UserConfig {
user_config.accept_forwards_to_priv_channels = false;
user_config.channel_handshake_config.announce_for_forwarding = false;
user_config.channel_handshake_limits.force_announced_channel_preference = true;

// A node that can't announce channels only accepts unannounced ones. LDK's default of 10%
// of the channel value in flight would cap every single incoming payment far below the
// inbound capacity, so we allow the counterparty to use all of it, as we already do for
// unannounced channels we open ourselves.
user_config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel =
100;
Comment thread
ovitrif marked this conversation as resolved.
}

user_config
Expand Down Expand Up @@ -1014,7 +1021,11 @@ pub enum AsyncPaymentsRole {
mod tests {
use std::str::FromStr;

use super::{may_announce_channel, AnnounceError, Config, NodeAlias, SocketAddress};
use lightning::util::config::UserConfig;

use super::{
default_user_config, may_announce_channel, AnnounceError, Config, NodeAlias, SocketAddress,
};

#[test]
fn node_announce_channel() {
Expand Down Expand Up @@ -1062,6 +1073,46 @@ mod tests {
assert!(may_announce_channel(&node_config).is_ok());
}

#[test]
fn inbound_htlc_value_in_flight_limit_follows_announce_ability() {
let default_percent = UserConfig::default()
.channel_handshake_config
.max_inbound_htlc_value_in_flight_percent_of_channel;
let percent_of = |config: &Config| {
default_user_config(config)
.channel_handshake_config
.max_inbound_htlc_value_in_flight_percent_of_channel
};
let alias = NodeAlias([1u8; 32]);
let address = SocketAddress::from_str("localhost:8000").unwrap();

// Neither alias nor listening addresses: the node can't announce, so the whole channel
// value may be in flight.
let mut node_config = Config::default();
assert!(may_announce_channel(&node_config).is_err());
assert_eq!(percent_of(&node_config), 100);

// Missing listening addresses only.
node_config.node_alias = Some(alias);
assert_eq!(
may_announce_channel(&node_config),
Err(AnnounceError::MissingListeningAddresses)
);
assert_eq!(percent_of(&node_config), 100);

// Missing node alias only.
node_config.node_alias = None;
node_config.listening_addresses = Some(vec![address]);
assert_eq!(may_announce_channel(&node_config), Err(AnnounceError::MissingNodeAlias));
assert_eq!(percent_of(&node_config), 100);

// A node that can announce channels keeps LDK's default.
node_config.node_alias = Some(alias);
assert!(may_announce_channel(&node_config).is_ok());
assert_eq!(percent_of(&node_config), default_percent);
assert!(default_percent < 100);
}

#[test]
fn onchain_wallet_account_helpers() {
use super::{AddressType, OnchainWalletAccount, MAX_ONCHAIN_WALLET_ACCOUNT_INDEX};
Expand Down
62 changes: 62 additions & 0 deletions tests/integration_tests_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3588,3 +3588,65 @@ async fn electrum_connection_timeout_above_max_is_capped() {
node.sync_wallets().unwrap();
node.stop().unwrap();
}

// A node that cannot announce channels (no node alias, as in the mobile apps) only accepts
// unannounced channels. It must let the counterparty put the whole channel value in flight
// instead of LDK's default of 10%, otherwise a single payment above that limit cannot be
// received even though the channel has the capacity.
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn inbound_htlc_in_flight_limit_for_unannounced_node() {
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
let chain_source = TestChainSource::Esplora(&electrsd);

let config_a = random_config(true);
let node_a = setup_node(&chain_source, config_a, None);

let mut config_b = random_config(true);
config_b.node_config.node_alias = None;
let node_b = setup_node(&chain_source, config_b, None);

let addr_a = node_a.onchain_payment().new_address().unwrap();
premine_and_distribute_funds(
&bitcoind.client,
&electrsd.client,
vec![addr_a],
Amount::from_sat(2_000_000),
)
.await;
node_a.sync_wallets().unwrap();
node_b.sync_wallets().unwrap();

let channel_value_sat = 1_000_000;
open_channel(&node_a, &node_b, channel_value_sat, false, &electrsd).await;
generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await;
node_a.sync_wallets().unwrap();
node_b.sync_wallets().unwrap();
expect_channel_ready_event!(node_a, node_b.node_id());
expect_channel_ready_event!(node_b, node_a.node_id());

let description =
Bolt11InvoiceDescription::Direct(Description::new(String::from("inbound")).unwrap());

// 9% of the channel value is below LDK's default limit and always worked.
let below_limit_msat = channel_value_sat * 1000 * 9 / 100;
let invoice = node_b
.bolt11_payment()
.receive(below_limit_msat, &description.clone().into(), 9217)
.unwrap();
let payment_id = node_a.bolt11_payment().send(&invoice, None).unwrap();
expect_payment_successful_event!(node_a, Some(payment_id), None);
expect_payment_received_event!(node_b, below_limit_msat);

// 20% of the channel value used to fail because node B advertised a 10% in-flight limit.
let above_limit_msat = channel_value_sat * 1000 * 20 / 100;
let invoice = node_b
.bolt11_payment()
.receive(above_limit_msat, &description.clone().into(), 9217)
.unwrap();
let payment_id = node_a
.bolt11_payment()
.send(&invoice, None)
.expect("a payment above 10% of the channel value must be routable");
expect_payment_successful_event!(node_a, Some(payment_id), None);
expect_payment_received_event!(node_b, above_limit_msat);
}