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
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1449,8 +1449,8 @@ impl Node {
/// Connect to a node and open a new unannounced channel, in which the target node can
/// spend its entire balance.
///
/// This channel allows the target node to try to steal your funds with no financial
/// penalty, so this channel should only be opened to nodes you trust.
/// This channel allows the target node to try to steal your channel balance with no
/// financial penalty, so this channel should only be opened to nodes you trust.
///
/// Disconnects and reconnects are handled automatically.
///
Expand Down Expand Up @@ -1484,8 +1484,8 @@ impl Node {
/// minus fees and anchor reserves. The target node will be able to spend its entire channel
/// balance.
///
/// This channel allows the target node to try to steal your funds with no financial
/// penalty, so this channel should only be opened to nodes you trust.
/// This channel allows the target node to try to steal your channel balance with no
/// financial penalty, so this channel should only be opened to nodes you trust.
///
/// Disconnects and reconnects are handled automatically.
///
Expand Down
12 changes: 6 additions & 6 deletions src/liquidity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,10 @@ pub struct LSPS2ServiceConfig {
///
/// [`bLIP-52`]: https://github.com/lightning/blips/blob/master/blip-0052.md#trust-models
pub client_trusts_lsp: bool,
/// When set, clients that we open channels to will be allowed to spend their entire channel
/// balance. This allows clients to try to steal your funds with no financial penalty, so
/// this should only be set if you trust your clients.
pub allow_client_0reserve: bool,
/// When set, we will allow clients to spend their entire channel balance in the channels
/// we open to them. This allows clients to try to steal your channel balance with
/// no financial penalty, so this should only be set if you trust your clients.
pub disable_client_reserve: bool,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, if we really want to rename this field, it would still be good to mention '0-reserve' somewhere, as this is what we use elsewhere in the API to refer to this feature.

}

pub(crate) struct LiquiditySourceBuilder<L: Deref>
Expand Down Expand Up @@ -792,7 +792,7 @@ where
config.channel_config.forwarding_fee_base_msat = 0;
config.channel_config.forwarding_fee_proportional_millionths = 0;

let result = if service_config.allow_client_0reserve {
let result = if service_config.disable_client_reserve {
self.channel_manager.create_channel_to_trusted_peer_0reserve(
their_network_key,
channel_amount_sats,
Expand All @@ -819,7 +819,7 @@ where
// the pending requests and regularly retry opening the channel until we
// succeed.
let zero_reserve_string =
if service_config.allow_client_0reserve { "0reserve " } else { "" };
if service_config.disable_client_reserve { "0reserve " } else { "" };
log_error!(
self.logger,
"Failed to open LSPS2 {}channel to {}: {:?}",
Expand Down
81 changes: 71 additions & 10 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -790,7 +790,7 @@ pub async fn splice_in_with_all(

pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
node_a: TestNode, node_b: TestNode, bitcoind: &BitcoindClient, electrsd: &E, allow_0conf: bool,
expect_anchor_channel: bool, force_close: bool,
allow_0reserve: bool, expect_anchor_channel: bool, force_close: bool,
) {
let addr_a = node_a.onchain_payment().new_address().unwrap();
let addr_b = node_b.onchain_payment().new_address().unwrap();
Expand Down Expand Up @@ -846,15 +846,27 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
println!("\nA -- open_channel -> B");
let funding_amount_sat = 2_080_000;
let push_msat = (funding_amount_sat / 2) * 1000; // balance the channel
node_a
.open_announced_channel(
node_b.node_id(),
node_b.listening_addresses().unwrap().first().unwrap().clone(),
funding_amount_sat,
Some(push_msat),
None,
)
.unwrap();
if allow_0reserve {
node_a
.open_0reserve_channel(
node_b.node_id(),
node_b.listening_addresses().unwrap().first().unwrap().clone(),
funding_amount_sat,
Some(push_msat),
None,
)
.unwrap();
} else {
node_a
.open_announced_channel(
node_b.node_id(),
node_b.listening_addresses().unwrap().first().unwrap().clone(),
funding_amount_sat,
Some(push_msat),
None,
)
.unwrap();
}

assert_eq!(node_a.list_peers().first().unwrap().node_id, node_b.node_id());
assert!(node_a.list_peers().first().unwrap().is_persisted);
Expand Down Expand Up @@ -913,6 +925,22 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
node_b_anchor_reserve_sat
);

// Note that only node B has 0-reserve, we don't yet have an API to allow the opener of the
// channel to have 0-reserve.
if allow_0reserve {
assert_eq!(node_b.list_channels()[0].unspendable_punishment_reserve, Some(0));
assert_eq!(node_b.list_channels()[0].outbound_capacity_msat, push_msat);
assert_eq!(node_b.list_channels()[0].next_outbound_htlc_limit_msat, push_msat);

assert_eq!(node_b.list_balances().total_lightning_balance_sats * 1000, push_msat);
let LightningBalance::ClaimableOnChannelClose { amount_satoshis, .. } =
node_b.list_balances().lightning_balances[0]
else {
panic!("Unexpected `LightningBalance` variant");
};
assert_eq!(amount_satoshis * 1000, push_msat);
}

let user_channel_id_a = expect_channel_ready_event!(node_a, node_b.node_id());
let user_channel_id_b = expect_channel_ready_event!(node_b, node_a.node_id());

Expand Down Expand Up @@ -1267,6 +1295,39 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
2
);

if allow_0reserve {
let node_a_outbound_capacity_msat = node_a.list_channels()[0].outbound_capacity_msat;
let node_a_reserve_msat =
node_a.list_channels()[0].unspendable_punishment_reserve.unwrap() * 1000;
// TODO: Zero-fee commitment channels are anchor channels, but do not allocate any
// funds to the anchor, so this will need to be updated when we ship these channels
// in ldk-node.
let node_a_anchors_msat = if expect_anchor_channel { 2 * 330 * 1000 } else { 0 };
let funding_amount_msat = node_a.list_channels()[0].channel_value_sats * 1000;
// Node B does not have any reserve, so we only subtract a few items on node A's
// side to arrive at node B's capacity
let node_b_capacity_msat = funding_amount_msat
- node_a_outbound_capacity_msat
- node_a_reserve_msat
- node_a_anchors_msat;
let got_capacity_msat = node_b.list_channels()[0].outbound_capacity_msat;
assert_eq!(got_capacity_msat, node_b_capacity_msat);
assert_ne!(got_capacity_msat, 0);
// Sanity check to make sure this is a non-trivial amount
assert!(got_capacity_msat > 15_000_000);

// This is a private channel, so node B can send 100% of the value over
assert_eq!(node_b.list_channels()[0].next_outbound_htlc_limit_msat, node_b_capacity_msat);

node_b.spontaneous_payment().send(node_b_capacity_msat, node_a.node_id(), None).unwrap();
expect_event!(node_b, PaymentSuccessful);
expect_event!(node_a, PaymentReceived);

node_a.spontaneous_payment().send(node_b_capacity_msat, node_b.node_id(), None).unwrap();
expect_event!(node_a, PaymentSuccessful);
expect_event!(node_b, PaymentReceived);
}

println!("\nB close_channel (force: {})", force_close);
tokio::time::sleep(Duration::from_secs(1)).await;
if force_close {
Expand Down
107 changes: 94 additions & 13 deletions tests/integration_tests_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,44 +48,125 @@ async fn channel_full_cycle() {
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
let chain_source = random_chain_source(&bitcoind, &electrsd);
let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false);
do_channel_full_cycle(node_a, node_b, &bitcoind.client, &electrsd.client, false, true, false)
.await;
do_channel_full_cycle(
node_a,
node_b,
&bitcoind.client,
&electrsd.client,
false,
false,
true,
false,
)
.await;
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn channel_full_cycle_force_close() {
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
let chain_source = random_chain_source(&bitcoind, &electrsd);
let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false);
do_channel_full_cycle(node_a, node_b, &bitcoind.client, &electrsd.client, false, true, true)
.await;
do_channel_full_cycle(
node_a,
node_b,
&bitcoind.client,
&electrsd.client,
false,
false,
true,
true,
)
.await;
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn channel_full_cycle_force_close_trusted_no_reserve() {
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
let chain_source = random_chain_source(&bitcoind, &electrsd);
let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, true);
do_channel_full_cycle(node_a, node_b, &bitcoind.client, &electrsd.client, false, true, true)
.await;
do_channel_full_cycle(
node_a,
node_b,
&bitcoind.client,
&electrsd.client,
false,
false,
true,
true,
)
.await;
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn channel_full_cycle_0conf() {
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
let chain_source = random_chain_source(&bitcoind, &electrsd);
let (node_a, node_b) = setup_two_nodes(&chain_source, true, true, false);
do_channel_full_cycle(node_a, node_b, &bitcoind.client, &electrsd.client, true, true, false)
.await;
do_channel_full_cycle(
node_a,
node_b,
&bitcoind.client,
&electrsd.client,
true,
false,
true,
false,
)
.await;
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn channel_full_cycle_legacy_staticremotekey() {
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
let chain_source = random_chain_source(&bitcoind, &electrsd);
let (node_a, node_b) = setup_two_nodes(&chain_source, false, false, false);
do_channel_full_cycle(node_a, node_b, &bitcoind.client, &electrsd.client, false, false, false)
.await;
do_channel_full_cycle(
node_a,
node_b,
&bitcoind.client,
&electrsd.client,
false,
false,
false,
false,
)
.await;
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn channel_full_cycle_0reserve() {
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
let chain_source = random_chain_source(&bitcoind, &electrsd);
let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false);
do_channel_full_cycle(
node_a,
node_b,
&bitcoind.client,
&electrsd.client,
false,
true,
true,
false,
)
.await;
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn channel_full_cycle_0conf_0reserve() {
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
let chain_source = random_chain_source(&bitcoind, &electrsd);
let (node_a, node_b) = setup_two_nodes(&chain_source, true, true, false);
do_channel_full_cycle(
node_a,
node_b,
&bitcoind.client,
&electrsd.client,
true,
true,
true,
false,
)
.await;
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
Expand Down Expand Up @@ -1705,7 +1786,7 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) {
min_channel_opening_fee_msat: 0,
max_client_to_self_delay: 1024,
client_trusts_lsp,
allow_client_0reserve: false,
disable_client_reserve: false,
};

let service_config = random_config(true);
Expand Down Expand Up @@ -2024,7 +2105,7 @@ async fn lsps2_client_trusts_lsp() {
min_channel_opening_fee_msat: 0,
max_client_to_self_delay: 1024,
client_trusts_lsp: true,
allow_client_0reserve: false,
disable_client_reserve: false,
};

let service_config = random_config(true);
Expand Down Expand Up @@ -2199,7 +2280,7 @@ async fn lsps2_lsp_trusts_client_but_client_does_not_claim() {
min_channel_opening_fee_msat: 0,
max_client_to_self_delay: 1024,
client_trusts_lsp: false,
allow_client_0reserve: false,
disable_client_reserve: false,
};

let service_config = random_config(true);
Expand Down
1 change: 1 addition & 0 deletions tests/integration_tests_vss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ async fn channel_full_cycle_with_vss_store() {
&bitcoind.client,
&electrsd.client,
false,
false,
true,
false,
)
Expand Down