Skip to content

Commit c199697

Browse files
committed
Add test coverage for the ban on 0-reserve legacy channels
1 parent 7ccc6b7 commit c199697

1 file changed

Lines changed: 189 additions & 1 deletion

File tree

lightning/src/ln/channel_open_tests.rs

Lines changed: 189 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ use crate::ln::channelmanager::{
2424
MAX_UNFUNDED_CHANS_PER_PEER,
2525
};
2626
use crate::ln::msgs::{
27-
AcceptChannel, BaseMessageHandler, ChannelMessageHandler, ErrorAction, MessageSendEvent,
27+
AcceptChannel, BaseMessageHandler, ChannelMessageHandler, ErrorAction, ErrorMessage,
28+
MessageSendEvent,
2829
};
2930
use crate::ln::types::ChannelId;
3031
use crate::ln::{functional_test_utils::*, msgs};
@@ -48,6 +49,7 @@ use bitcoin::{Amount, Sequence, Transaction, TxIn, TxOut, Witness};
4849
use lightning_macros::xtest;
4950

5051
use lightning_types::features::ChannelTypeFeatures;
52+
use types::string::UntrustedString;
5153

5254
#[test]
5355
fn test_outbound_chans_unlimited() {
@@ -2496,3 +2498,189 @@ fn test_fund_pending_channel() {
24962498
};
24972499
check_closed_event(&nodes[0], 1, reason, &[node_b_id], 100_000);
24982500
}
2501+
2502+
#[xtest(feature = "_externalize_tests")]
2503+
fn test_holder_selected_0reserve_on_legacy_channel_is_not_allowed() {
2504+
{
2505+
let chanmon_cfgs = create_chanmon_cfgs(2);
2506+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
2507+
let mut channel_config = test_default_channel_config();
2508+
assert!(channel_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx);
2509+
let node_chanmgrs = create_node_chanmgrs(
2510+
2,
2511+
&node_cfgs,
2512+
&[Some(channel_config.clone()), Some(channel_config.clone())],
2513+
);
2514+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
2515+
2516+
let _node_a_id = nodes[0].node.get_our_node_id();
2517+
let node_b_id = nodes[1].node.get_our_node_id();
2518+
2519+
let mut legacy_channel_config = test_default_channel_config();
2520+
legacy_channel_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = false;
2521+
legacy_channel_config.channel_handshake_config.negotiate_anchor_zero_fee_commitments =
2522+
false;
2523+
2524+
// User tries to open a legacy 0-reserve channel with a config override, we fail
2525+
assert_eq!(
2526+
nodes[0]
2527+
.node
2528+
.create_channel_to_trusted_peer_0reserve(
2529+
node_b_id,
2530+
100_000,
2531+
0,
2532+
42,
2533+
None,
2534+
Some(legacy_channel_config)
2535+
)
2536+
.unwrap_err(),
2537+
APIError::APIMisuseError {
2538+
err: "0-reserve is not allowed on legacy channels".to_owned()
2539+
}
2540+
);
2541+
}
2542+
{
2543+
let chanmon_cfgs = create_chanmon_cfgs(2);
2544+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
2545+
let mut channel_config = test_default_channel_config();
2546+
channel_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = false;
2547+
channel_config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = false;
2548+
let node_chanmgrs = create_node_chanmgrs(
2549+
2,
2550+
&node_cfgs,
2551+
&[Some(channel_config.clone()), Some(channel_config.clone())],
2552+
);
2553+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
2554+
2555+
let _node_a_id = nodes[0].node.get_our_node_id();
2556+
let node_b_id = nodes[1].node.get_our_node_id();
2557+
2558+
// User tries to open a legacy 0-reserve channel from the default config, we fail
2559+
assert_eq!(
2560+
nodes[0]
2561+
.node
2562+
.create_channel_to_trusted_peer_0reserve(node_b_id, 100_000, 0, 42, None, None)
2563+
.unwrap_err(),
2564+
APIError::APIMisuseError {
2565+
err: "0-reserve is not allowed on legacy channels".to_owned()
2566+
}
2567+
);
2568+
}
2569+
2570+
let chanmon_cfgs = create_chanmon_cfgs(2);
2571+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
2572+
let mut channel_config = test_default_channel_config();
2573+
channel_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = false;
2574+
channel_config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = false;
2575+
let node_chanmgrs = create_node_chanmgrs(
2576+
2,
2577+
&node_cfgs,
2578+
&[Some(channel_config.clone()), Some(channel_config.clone())],
2579+
);
2580+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
2581+
2582+
let node_a_id = nodes[0].node.get_our_node_id();
2583+
let node_b_id = nodes[1].node.get_our_node_id();
2584+
2585+
nodes[0].node.create_channel(node_b_id, 100_000, 0, 42, None, None).unwrap();
2586+
let mut open_channel_msg_0reserve =
2587+
get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, node_b_id);
2588+
open_channel_msg_0reserve.channel_reserve_satoshis = 0;
2589+
assert_eq!(
2590+
open_channel_msg_0reserve.common_fields.channel_type,
2591+
Some(ChannelTypeFeatures::only_static_remote_key())
2592+
);
2593+
2594+
// User accepts a legacy channel, and sets 0-reserve for the counterparty, we fail
2595+
nodes[1].node.handle_open_channel(node_a_id, &open_channel_msg_0reserve);
2596+
let events = nodes[1].node.get_and_clear_pending_events();
2597+
match events[0] {
2598+
Event::OpenChannelRequest { temporary_channel_id, .. } => {
2599+
let error = nodes[1]
2600+
.node
2601+
.accept_inbound_channel_from_trusted_peer(
2602+
&temporary_channel_id,
2603+
&node_a_id,
2604+
42,
2605+
TrustedChannelFeatures::ZeroReserve,
2606+
None,
2607+
)
2608+
.unwrap_err();
2609+
assert_eq!(
2610+
error,
2611+
APIError::ChannelUnavailable {
2612+
err: "0-reserve is not allowed on legacy channels".to_owned()
2613+
}
2614+
);
2615+
},
2616+
_ => panic!("Unexpected event"),
2617+
}
2618+
let err_msg = get_err_msg(&nodes[1], &node_a_id);
2619+
assert_eq!(
2620+
err_msg,
2621+
ErrorMessage {
2622+
channel_id: open_channel_msg_0reserve.common_fields.temporary_channel_id,
2623+
data: "0-reserve is not allowed on legacy channels".to_string()
2624+
}
2625+
);
2626+
2627+
// But legacy channels where only the counterparty sets 0-reserve are ok!
2628+
// Here node 1 accepts 0-reserve from node 0, and node 1 sets some non-zero reserve...
2629+
handle_and_accept_open_channel(&nodes[1], node_a_id, &open_channel_msg_0reserve);
2630+
let mut accept_channel_msg =
2631+
get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, node_a_id);
2632+
// Override the reserve selected by node 1, make sure node 0 accepts too
2633+
accept_channel_msg.channel_reserve_satoshis = 0;
2634+
2635+
nodes[0].node.handle_accept_channel(node_b_id, &accept_channel_msg);
2636+
2637+
let events = nodes[0].node.get_and_clear_pending_events();
2638+
assert_eq!(events.len(), 1);
2639+
assert!(
2640+
matches!(events[0], Event::FundingGenerationReady { channel_value_satoshis: 100_000, user_channel_id: 42, counterparty_node_id, .. } if counterparty_node_id == node_b_id)
2641+
);
2642+
}
2643+
2644+
#[xtest(feature = "_externalize_tests")]
2645+
fn test_error_if_0reserve_negotiates_down_to_legacy() {
2646+
let chanmon_cfgs = create_chanmon_cfgs(2);
2647+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
2648+
let channel_config = test_default_channel_config();
2649+
assert!(channel_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx);
2650+
let node_chanmgrs = create_node_chanmgrs(
2651+
2,
2652+
&node_cfgs,
2653+
&[Some(channel_config.clone()), Some(channel_config.clone())],
2654+
);
2655+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
2656+
2657+
let node_b_id = nodes[1].node.get_our_node_id();
2658+
2659+
nodes[0]
2660+
.node
2661+
.create_channel_to_trusted_peer_0reserve(node_b_id, 100_000, 0, 42, None, None)
2662+
.unwrap();
2663+
let open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, node_b_id);
2664+
assert_eq!(
2665+
open_channel_msg.common_fields.channel_type,
2666+
Some(ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies())
2667+
);
2668+
assert_eq!(open_channel_msg.channel_reserve_satoshis, 0);
2669+
2670+
let reason = "Don't like your channel".to_owned();
2671+
nodes[0].node.handle_error(
2672+
node_b_id,
2673+
&ErrorMessage {
2674+
channel_id: open_channel_msg.common_fields.temporary_channel_id,
2675+
data: reason.clone(),
2676+
},
2677+
);
2678+
2679+
let reason = ClosureReason::CounterpartyForceClosed { peer_msg: UntrustedString(reason) };
2680+
let expected_closing = ExpectedCloseEvent::from_id_reason(
2681+
open_channel_msg.common_fields.temporary_channel_id,
2682+
false,
2683+
reason,
2684+
);
2685+
check_closed_events(&nodes[0], &[expected_closing]);
2686+
}

0 commit comments

Comments
 (0)