Skip to content

Commit ea95a15

Browse files
Test manual broadcast tracking and holder commit flow
Tests that holder commitment broadcasts are properly deferred until funding confirms, and that the full manual-funding flow works correctly.
1 parent be1955a commit ea95a15

File tree

3 files changed

+258
-1
lines changed

3 files changed

+258
-1
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7373,7 +7373,7 @@ mod tests {
73737373
let monitor = ChannelMonitor::new(
73747374
Secp256k1::new(), keys, Some(shutdown_script.into_inner()), 0, &ScriptBuf::new(),
73757375
&channel_parameters, true, 0, HolderCommitmentTransaction::dummy(0, funding_outpoint, Vec::new()),
7376-
best_block, dummy_key, channel_id, false
7376+
best_block, dummy_key, channel_id, false,
73777377
);
73787378

73797379
let chan_id = monitor.inner.lock().unwrap().channel_id();

lightning/src/ln/functional_test_utils.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1804,6 +1804,66 @@ pub fn create_chan_between_nodes_with_value_a<'a, 'b, 'c: 'd, 'd>(
18041804
(msgs, chan_id, tx)
18051805
}
18061806

1807+
pub fn create_channel_manual_funding<'a, 'b, 'c: 'd, 'd>(
1808+
nodes: &'a Vec<Node<'b, 'c, 'd>>, initiator: usize, counterparty: usize, channel_value: u64,
1809+
push_msat: u64,
1810+
) -> (ChannelId, Transaction, OutPoint) {
1811+
let node_a = &nodes[initiator];
1812+
let node_b = &nodes[counterparty];
1813+
let node_a_id = node_a.node.get_our_node_id();
1814+
let node_b_id = node_b.node.get_our_node_id();
1815+
1816+
let temp_channel_id = exchange_open_accept_chan(node_a, node_b, channel_value, push_msat);
1817+
1818+
let (funding_temp_id, funding_tx, funding_outpoint) =
1819+
create_funding_transaction(node_a, &node_b_id, channel_value, 42);
1820+
assert_eq!(temp_channel_id, funding_temp_id);
1821+
1822+
node_a
1823+
.node
1824+
.funding_transaction_generated_manual_broadcast(
1825+
funding_temp_id,
1826+
node_b_id,
1827+
funding_tx.clone(),
1828+
)
1829+
.unwrap();
1830+
check_added_monitors!(node_a, 0);
1831+
1832+
let funding_created = get_event_msg!(node_a, MessageSendEvent::SendFundingCreated, node_b_id);
1833+
node_b.node.handle_funding_created(node_a_id, &funding_created);
1834+
check_added_monitors!(node_b, 1);
1835+
let channel_id_b = expect_channel_pending_event(node_b, &node_a_id);
1836+
1837+
let funding_signed = get_event_msg!(node_b, MessageSendEvent::SendFundingSigned, node_a_id);
1838+
node_a.node.handle_funding_signed(node_b_id, &funding_signed);
1839+
check_added_monitors!(node_a, 1);
1840+
1841+
let events = node_a.node.get_and_clear_pending_events();
1842+
assert_eq!(events.len(), 2);
1843+
let funding_txid = funding_tx.compute_txid();
1844+
let mut channel_id = None;
1845+
for event in events {
1846+
match event {
1847+
Event::FundingTxBroadcastSafe { funding_txo, counterparty_node_id, .. } => {
1848+
assert_eq!(counterparty_node_id, node_b_id);
1849+
assert_eq!(funding_txo.txid, funding_txid);
1850+
assert_eq!(funding_txo.vout, u32::from(funding_outpoint.index));
1851+
},
1852+
Event::ChannelPending { channel_id: pending_id, counterparty_node_id, .. } => {
1853+
assert_eq!(counterparty_node_id, node_b_id);
1854+
channel_id = Some(pending_id);
1855+
},
1856+
_ => panic!("Unexpected event"),
1857+
}
1858+
}
1859+
let channel_id = channel_id.expect("channel pending event missing");
1860+
assert_eq!(channel_id, channel_id_b);
1861+
1862+
assert!(node_a.tx_broadcaster.txn_broadcasted.lock().unwrap().is_empty());
1863+
1864+
(channel_id, funding_tx, funding_outpoint)
1865+
}
1866+
18071867
pub fn create_chan_between_nodes_with_value_b<'a, 'b, 'c>(
18081868
node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>,
18091869
as_funding_msgs: &(msgs::ChannelReady, msgs::AnnouncementSignatures),

lightning/src/ln/functional_tests.rs

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::chain::channelmonitor::{
2020
};
2121
use crate::chain::transaction::OutPoint;
2222
use crate::chain::{ChannelMonitorUpdateStatus, Confirm, Listen, Watch};
23+
use crate::events::bump_transaction::BumpTransactionEvent;
2324
use crate::events::{
2425
ClosureReason, Event, HTLCHandlingFailureType, PathFailure, PaymentFailureReason,
2526
PaymentPurpose,
@@ -9628,6 +9629,202 @@ pub fn test_remove_expired_inbound_unfunded_channels() {
96289629
check_closed_event(&nodes[1], 1, reason, false, &[node_a_id], 100000);
96299630
}
96309631

9632+
#[test]
9633+
fn test_manual_broadcast_skips_commitment_until_funding_seen() {
9634+
let chanmon_cfgs = create_chanmon_cfgs(2);
9635+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
9636+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
9637+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
9638+
9639+
let node_b_id = nodes[1].node.get_our_node_id();
9640+
9641+
let (channel_id, funding_tx, funding_outpoint) =
9642+
create_channel_manual_funding(&nodes, 0, 1, 100_000, 10_000);
9643+
9644+
nodes[0]
9645+
.node
9646+
.force_close_broadcasting_latest_txn(&channel_id, &node_b_id, "manual close".to_owned())
9647+
.unwrap();
9648+
check_added_monitors!(&nodes[0], 1);
9649+
check_added_monitors!(&nodes[1], 0);
9650+
9651+
assert!(nodes[0].tx_broadcaster.txn_broadcast().is_empty());
9652+
nodes[0].node.get_and_clear_pending_msg_events();
9653+
nodes[1].node.get_and_clear_pending_msg_events();
9654+
let events = nodes[0].node.get_and_clear_pending_events();
9655+
assert_eq!(events.len(), 1);
9656+
match &events[0] {
9657+
Event::ChannelClosed {
9658+
reason: ClosureReason::HolderForceClosed { broadcasted_latest_txn, message },
9659+
counterparty_node_id: Some(id),
9660+
..
9661+
} => {
9662+
assert_eq!(*broadcasted_latest_txn, Some(true));
9663+
assert_eq!(message, "manual close");
9664+
assert_eq!(id, &node_b_id);
9665+
},
9666+
_ => panic!("Unexpected event"),
9667+
}
9668+
nodes[1].node.get_and_clear_pending_events();
9669+
9670+
let monitor_events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
9671+
assert!(monitor_events.is_empty());
9672+
9673+
confirm_transaction(&nodes[0], &funding_tx);
9674+
confirm_transaction(&nodes[1], &funding_tx);
9675+
nodes[0].node.get_and_clear_pending_msg_events();
9676+
nodes[1].node.get_and_clear_pending_msg_events();
9677+
9678+
{
9679+
let monitor = get_monitor!(&nodes[0], channel_id);
9680+
// manual override
9681+
monitor.broadcast_latest_holder_commitment_txn(
9682+
&nodes[0].tx_broadcaster,
9683+
&nodes[0].fee_estimator,
9684+
&nodes[0].logger,
9685+
);
9686+
}
9687+
let funding_txid = funding_tx.compute_txid();
9688+
let broadcasts = nodes[0].tx_broadcaster.txn_broadcast();
9689+
assert!(!broadcasts.is_empty());
9690+
let commitment_tx = broadcasts
9691+
.iter()
9692+
.find(|tx| {
9693+
tx.input.iter().any(|input| {
9694+
input.previous_output.txid == funding_txid
9695+
&& input.previous_output.vout == u32::from(funding_outpoint.index)
9696+
})
9697+
})
9698+
.expect("commitment transaction not broadcast");
9699+
check_spends!(commitment_tx, funding_tx);
9700+
assert_eq!(commitment_tx.input.len(), 1);
9701+
let commitment_input = &commitment_tx.input[0];
9702+
assert_eq!(commitment_input.previous_output.txid, funding_txid);
9703+
assert_eq!(commitment_input.previous_output.vout, u32::from(funding_outpoint.index));
9704+
9705+
let monitor_events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
9706+
assert!(monitor_events.iter().all(|event| !matches!(event, Event::BumpTransaction(_))));
9707+
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
9708+
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
9709+
}
9710+
9711+
#[test]
9712+
fn test_manual_broadcast_detects_funding_and_broadcasts_on_timeout() {
9713+
let chanmon_cfgs = create_chanmon_cfgs(2);
9714+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
9715+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
9716+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
9717+
9718+
let node_b_id = nodes[1].node.get_our_node_id();
9719+
9720+
let (channel_id, funding_tx, funding_outpoint) =
9721+
create_channel_manual_funding(&nodes, 0, 1, 100_000, 10_000);
9722+
9723+
let funding_msgs =
9724+
create_chan_between_nodes_with_value_confirm(&nodes[0], &nodes[1], &funding_tx);
9725+
let confirmed_channel_id = funding_msgs.1;
9726+
assert_eq!(confirmed_channel_id, channel_id);
9727+
let _announcements =
9728+
create_chan_between_nodes_with_value_b(&nodes[0], &nodes[1], &funding_msgs.0);
9729+
9730+
let usable_channels = nodes[0].node.list_usable_channels();
9731+
assert_eq!(usable_channels.len(), 1);
9732+
assert_eq!(usable_channels[0].channel_id, channel_id);
9733+
9734+
let (_payment_preimage, _payment_hash, _payment_secret, _payment_id) =
9735+
route_payment(&nodes[0], &[&nodes[1]], 10_000_000);
9736+
nodes[1].node.get_and_clear_pending_events();
9737+
9738+
connect_blocks(&nodes[0], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
9739+
connect_blocks(&nodes[1], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
9740+
9741+
let events = nodes[0].node.get_and_clear_pending_events();
9742+
assert!(events.iter().any(|event| matches!(
9743+
event,
9744+
Event::ChannelClosed {
9745+
reason: ClosureReason::HTLCsTimedOut { .. },
9746+
counterparty_node_id: Some(id),
9747+
..
9748+
} if id == &node_b_id
9749+
)));
9750+
nodes[1].node.get_and_clear_pending_events();
9751+
nodes[0].node.get_and_clear_pending_msg_events();
9752+
nodes[1].node.get_and_clear_pending_msg_events();
9753+
check_added_monitors!(&nodes[0], 1);
9754+
check_added_monitors!(&nodes[1], 0);
9755+
9756+
let funding_txid = funding_tx.compute_txid();
9757+
let broadcasts = nodes[0].tx_broadcaster.txn_broadcast();
9758+
assert!(!broadcasts.is_empty());
9759+
let commitment_tx = broadcasts
9760+
.iter()
9761+
.find(|tx| {
9762+
tx.input.iter().any(|input| {
9763+
input.previous_output.txid == funding_txid
9764+
&& input.previous_output.vout == u32::from(funding_outpoint.index)
9765+
})
9766+
})
9767+
.expect("commitment transaction not broadcast");
9768+
check_spends!(commitment_tx, funding_tx);
9769+
assert_eq!(commitment_tx.input.len(), 1);
9770+
9771+
for event in nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events() {
9772+
if let Event::BumpTransaction(bump_event) = event {
9773+
if let BumpTransactionEvent::ChannelClose {
9774+
channel_id: event_channel_id,
9775+
counterparty_node_id,
9776+
..
9777+
} = &bump_event
9778+
{
9779+
assert_eq!(*event_channel_id, channel_id);
9780+
assert_eq!(*counterparty_node_id, node_b_id);
9781+
}
9782+
nodes[0].bump_tx_handler.handle_event(&bump_event);
9783+
}
9784+
}
9785+
}
9786+
9787+
#[test]
9788+
fn test_manual_broadcast_no_bump_events_before_funding_seen() {
9789+
let chanmon_cfgs = create_chanmon_cfgs(2);
9790+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
9791+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
9792+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
9793+
9794+
let node_b_id = nodes[1].node.get_our_node_id();
9795+
9796+
let (channel_id, _, _) = create_channel_manual_funding(&nodes, 0, 1, 100_000, 10_000);
9797+
9798+
nodes[0]
9799+
.node
9800+
.force_close_broadcasting_latest_txn(&channel_id, &node_b_id, "manual close".to_owned())
9801+
.unwrap();
9802+
check_added_monitors!(&nodes[0], 1);
9803+
check_added_monitors!(&nodes[1], 0);
9804+
9805+
assert!(nodes[0].tx_broadcaster.txn_broadcast().is_empty());
9806+
nodes[0].node.get_and_clear_pending_msg_events();
9807+
nodes[1].node.get_and_clear_pending_msg_events();
9808+
let events = nodes[0].node.get_and_clear_pending_events();
9809+
assert_eq!(events.len(), 1);
9810+
match &events[0] {
9811+
Event::ChannelClosed {
9812+
reason: ClosureReason::HolderForceClosed { broadcasted_latest_txn, message },
9813+
counterparty_node_id: Some(id),
9814+
..
9815+
} => {
9816+
assert_eq!(*broadcasted_latest_txn, Some(true));
9817+
assert_eq!(message, "manual close");
9818+
assert_eq!(id, &node_b_id);
9819+
},
9820+
_ => panic!("Unexpected event"),
9821+
}
9822+
nodes[1].node.get_and_clear_pending_events();
9823+
9824+
let monitor_events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
9825+
assert!(monitor_events.iter().all(|event| !matches!(event, Event::BumpTransaction(_))));
9826+
}
9827+
96319828
fn do_test_multi_post_event_actions(do_reload: bool) {
96329829
// Tests handling multiple post-Event actions at once.
96339830
// There is specific code in ChannelManager to handle channels where multiple post-Event

0 commit comments

Comments
 (0)