Add expect_splice_failed_events helper
What changed, and why it matters
This commit only adds and uses a new test helper function. It makes existing tests check more details when a Lightning channel splice fails, but it does not change any production code or fix a security bug. There is no security relevance.
No security action needed. Treat as a normal test-quality improvement.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces expect_splice_failed_events in functional_test_utils.rs and replaces several ad-hoc Event::SpliceFailed assertions in splicing_tests.rs with calls to this helper. The helper verifies that a SpliceFailed event carries the expected channel_id, contributed_inputs, and contributed_outputs. This is purely a test-code refactor that strengthens test assertions; no runtime behavior of the Lightning node is modified.
Changed components
lightning/src/ln/functional_test_utils.rslightning/src/ln/splicing_tests.rsInspect captured patch +34 / −25
diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs
index 16616e5..91e05d2 100644
--- a/lightning/src/ln/functional_test_utils.rs
+++ b/lightning/src/ln/functional_test_utils.rs
@@ -27,7 +27,7 @@ use crate::ln::channelmanager::{
AChannelManager, ChainParameters, ChannelManager, ChannelManagerReadArgs, PaymentId,
RAACommitmentOrder, MIN_CLTV_EXPIRY_DELTA,
};
-use crate::ln::funding::FundingTxInput;
+use crate::ln::funding::{FundingContribution, FundingTxInput};
use crate::ln::msgs::{self, OpenChannel};
use crate::ln::msgs::{
BaseMessageHandler, ChannelMessageHandler, MessageSendEvent, RoutingMessageHandler,
@@ -3232,6 +3232,25 @@ pub fn expect_splice_pending_event<'a, 'b, 'c, 'd>(
}
}
+#[cfg(any(test, ldk_bench, feature = "_test_utils"))]
+pub fn expect_splice_failed_events<'a, 'b, 'c, 'd>(
+ node: &'a Node<'b, 'c, 'd>, expected_channel_id: &ChannelId,
+ funding_contribution: FundingContribution,
+) {
+ let events = node.node.get_and_clear_pending_events();
+ assert_eq!(events.len(), 1);
+ match &events[0] {
+ Event::SpliceFailed { channel_id, contributed_inputs, contributed_outputs, .. } => {
+ assert_eq!(*expected_channel_id, *channel_id);
+ let (expected_inputs, expected_outputs) =
+ funding_contribution.into_contributed_inputs_and_outputs();
+ assert_eq!(*contributed_inputs, expected_inputs);
+ assert_eq!(*contributed_outputs, expected_outputs);
+ },
+ _ => panic!("Unexpected event"),
+ }
+}
+
pub fn expect_probe_successful_events(
node: &Node, mut probe_results: Vec<(PaymentHash, PaymentId)>,
) {
diff --git a/lightning/src/ln/splicing_tests.rs b/lightning/src/ln/splicing_tests.rs
index 1e9ecf9..0c7df06 100644
--- a/lightning/src/ln/splicing_tests.rs
+++ b/lightning/src/ln/splicing_tests.rs
@@ -548,7 +548,8 @@ fn do_test_splice_state_reset_on_disconnect(reload: bool) {
value: Amount::from_sat(1_000),
script_pubkey: nodes[0].wallet_source.get_change_script().unwrap(),
}];
- let _ = initiate_splice_out(&nodes[0], &nodes[1], channel_id, outputs.clone());
+ let funding_contribution =
+ initiate_splice_out(&nodes[0], &nodes[1], channel_id, outputs.clone());
// Attempt a splice negotiation that only goes up to receiving `splice_init`. Reconnecting
// should implicitly abort the negotiation and reset the splice state such that we're able to
@@ -586,14 +587,15 @@ fn do_test_splice_state_reset_on_disconnect(reload: bool) {
nodes[1].node.peer_disconnected(node_id_0);
}
- let _event = get_event!(nodes[0], Event::SpliceFailed);
+ expect_splice_failed_events(&nodes[0], &channel_id, funding_contribution);
let mut reconnect_args = ReconnectArgs::new(&nodes[0], &nodes[1]);
reconnect_args.send_channel_ready = (true, true);
reconnect_args.send_announcement_sigs = (true, true);
reconnect_nodes(reconnect_args);
- let _ = initiate_splice_out(&nodes[0], &nodes[1], channel_id, outputs.clone());
+ let funding_contribution =
+ initiate_splice_out(&nodes[0], &nodes[1], channel_id, outputs.clone());
// Attempt a splice negotiation that ends mid-construction of the funding transaction.
// Reconnecting should implicitly abort the negotiation and reset the splice state such that
@@ -636,14 +638,15 @@ fn do_test_splice_state_reset_on_disconnect(reload: bool) {
nodes[1].node.peer_disconnected(node_id_0);
}
- let _event = get_event!(nodes[0], Event::SpliceFailed);
+ expect_splice_failed_events(&nodes[0], &channel_id, funding_contribution);
let mut reconnect_args = ReconnectArgs::new(&nodes[0], &nodes[1]);
reconnect_args.send_channel_ready = (true, true);
reconnect_args.send_announcement_sigs = (true, true);
reconnect_nodes(reconnect_args);
- let _ = initiate_splice_out(&nodes[0], &nodes[1], channel_id, outputs.clone());
+ let funding_contribution =
+ initiate_splice_out(&nodes[0], &nodes[1], channel_id, outputs.clone());
// Attempt a splice negotiation that ends before the initial `commitment_signed` messages are
// exchanged. The node missing the other's `commitment_signed` upon reconnecting should
@@ -717,7 +720,7 @@ fn do_test_splice_state_reset_on_disconnect(reload: bool) {
let tx_abort = get_event_msg!(nodes[0], MessageSendEvent::SendTxAbort, node_id_1);
nodes[1].node.handle_tx_abort(node_id_0, &tx_abort);
- let _event = get_event!(nodes[0], Event::SpliceFailed);
+ expect_splice_failed_events(&nodes[0], &channel_id, funding_contribution);
// Attempt a splice negotiation that completes, (i.e. `tx_signatures` are exchanged). Reconnecting
// should not abort the negotiation or reset the splice state.
@@ -778,7 +781,8 @@ fn test_config_reject_inbound_splices() {
value: Amount::from_sat(1_000),
script_pubkey: nodes[0].wallet_source.get_change_script().unwrap(),
}];
- let _ = initiate_splice_out(&nodes[0], &nodes[1], channel_id, outputs.clone());
+ let funding_contribution =
+ initiate_splice_out(&nodes[0], &nodes[1], channel_id, outputs.clone());
let stfu = get_event_msg!(nodes[0], MessageSendEvent::SendStfu, node_id_1);
nodes[1].node.handle_stfu(node_id_0, &stfu);
@@ -799,7 +803,7 @@ fn test_config_reject_inbound_splices() {
nodes[0].node.peer_disconnected(node_id_1);
nodes[1].node.peer_disconnected(node_id_0);
- let _event = get_event!(nodes[0], Event::SpliceFailed);
+ expect_splice_failed_events(&nodes[0], &channel_id, funding_contribution);
let mut reconnect_args = ReconnectArgs::new(&nodes[0], &nodes[1]);
reconnect_args.send_channel_ready = (true, true);
@@ -2035,14 +2039,7 @@ fn fail_splice_on_interactive_tx_error() {
get_event_msg!(acceptor, MessageSendEvent::SendTxComplete, node_id_initiator);
initiator.node.handle_tx_add_input(node_id_acceptor, &tx_add_input);
- let event = get_event!(initiator, Event::SpliceFailed);
- match event {
- Event::SpliceFailed { contributed_inputs, .. } => {
- assert_eq!(contributed_inputs.len(), 1);
- assert_eq!(contributed_inputs[0], funding_contribution.into_tx_parts().0[0].outpoint());
- },
- _ => panic!("Expected Event::SpliceFailed"),
- }
+ expect_splice_failed_events(initiator, &channel_id, funding_contribution);
// We exit quiescence upon sending `tx_abort`, so we should see the holding cell be immediately
// freed.
@@ -2113,14 +2110,7 @@ fn fail_splice_on_tx_abort() {
let tx_abort = get_event_msg!(acceptor, MessageSendEvent::SendTxAbort, node_id_initiator);
initiator.node.handle_tx_abort(node_id_acceptor, &tx_abort);
- let event = get_event!(initiator, Event::SpliceFailed);
- match event {
- Event::SpliceFailed { contributed_inputs, .. } => {
- assert_eq!(contributed_inputs.len(), 1);
- assert_eq!(contributed_inputs[0], funding_contribution.into_tx_parts().0[0].outpoint());
- },
- _ => panic!("Expected Event::SpliceFailed"),
- }
+ expect_splice_failed_events(initiator, &channel_id, funding_contribution);
// We exit quiescence upon receiving `tx_abort`, so we should see our `tx_abort` echo and the
// holding cell be immediately freed.
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.