Skip to content

Commit 97f59e9

Browse files
committed
f - add test coverage
1 parent 9b2e748 commit 97f59e9

File tree

3 files changed

+168
-0
lines changed

3 files changed

+168
-0
lines changed

lightning/src/ln/channel.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11795,6 +11795,32 @@ where
1179511795
})
1179611796
}
1179711797

11798+
#[cfg(test)]
11799+
pub fn abandon_splice(
11800+
&mut self,
11801+
) -> Result<(msgs::TxAbort, Option<SpliceFundingFailed>), APIError> {
11802+
match self.should_reset_pending_splice_funding_negotiation() {
11803+
Some(true) => {
11804+
let tx_abort =
11805+
msgs::TxAbort { channel_id: self.context.channel_id(), data: Vec::new() };
11806+
let splice_funding_failed = self.reset_pending_splice_state();
11807+
Ok((tx_abort, splice_funding_failed))
11808+
},
11809+
Some(false) => Err(APIError::APIMisuseError {
11810+
err: format!(
11811+
"Channel {} splice cannot be abandoned; already received signatures",
11812+
self.context.channel_id(),
11813+
),
11814+
}),
11815+
None => Err(APIError::APIMisuseError {
11816+
err: format!(
11817+
"Channel {} splice cannot be abandoned; no pending splice",
11818+
self.context.channel_id(),
11819+
),
11820+
}),
11821+
}
11822+
}
11823+
1179811824
/// Checks during handling splice_init
1179911825
pub fn validate_splice_init(
1180011826
&self, msg: &msgs::SpliceInit, our_funding_contribution: SignedAmount,

lightning/src/ln/channelmanager.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4723,6 +4723,94 @@ where
47234723
}
47244724
}
47254725

4726+
#[cfg(test)]
4727+
pub(crate) fn abandon_splice(
4728+
&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey,
4729+
) -> Result<(), APIError> {
4730+
let mut res = Ok(());
4731+
PersistenceNotifierGuard::optionally_notify(self, || {
4732+
let result = self.internal_abandon_splice(channel_id, counterparty_node_id);
4733+
res = result;
4734+
match res {
4735+
Ok(_) => NotifyOption::SkipPersistHandleEvents,
4736+
Err(_) => NotifyOption::SkipPersistNoEvents,
4737+
}
4738+
});
4739+
res
4740+
}
4741+
4742+
#[cfg(test)]
4743+
fn internal_abandon_splice(
4744+
&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey,
4745+
) -> Result<(), APIError> {
4746+
let per_peer_state = self.per_peer_state.read().unwrap();
4747+
4748+
let peer_state_mutex = match per_peer_state.get(counterparty_node_id).ok_or_else(|| {
4749+
APIError::ChannelUnavailable {
4750+
err: format!("Can't find a peer matching the passed counterparty node_id {counterparty_node_id}"),
4751+
}
4752+
}) {
4753+
Ok(p) => p,
4754+
Err(e) => return Err(e),
4755+
};
4756+
4757+
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
4758+
let peer_state = &mut *peer_state_lock;
4759+
4760+
// Look for the channel
4761+
match peer_state.channel_by_id.entry(*channel_id) {
4762+
hash_map::Entry::Occupied(mut chan_phase_entry) => {
4763+
if !chan_phase_entry.get().context().is_connected() {
4764+
// TODO: We should probably support this, but right now `splice_channel` refuses when
4765+
// the peer is disconnected, so we just check it here.
4766+
return Err(APIError::ChannelUnavailable {
4767+
err: "Cannot abandon splice while peer is disconnected".to_owned(),
4768+
});
4769+
}
4770+
4771+
if let Some(chan) = chan_phase_entry.get_mut().as_funded_mut() {
4772+
let (tx_abort, splice_funding_failed) = chan.abandon_splice()?;
4773+
4774+
peer_state.pending_msg_events.push(MessageSendEvent::SendTxAbort {
4775+
node_id: *counterparty_node_id,
4776+
msg: tx_abort,
4777+
});
4778+
4779+
if let Some(splice_funding_failed) = splice_funding_failed {
4780+
let pending_events = &mut self.pending_events.lock().unwrap();
4781+
pending_events.push_back((
4782+
events::Event::SpliceFailed {
4783+
channel_id: *channel_id,
4784+
counterparty_node_id: *counterparty_node_id,
4785+
user_channel_id: chan.context.get_user_id(),
4786+
abandoned_funding_txo: splice_funding_failed.funding_txo,
4787+
channel_type: splice_funding_failed.channel_type,
4788+
contributed_inputs: splice_funding_failed.contributed_inputs,
4789+
contributed_outputs: splice_funding_failed.contributed_outputs,
4790+
},
4791+
None,
4792+
));
4793+
}
4794+
4795+
Ok(())
4796+
} else {
4797+
Err(APIError::ChannelUnavailable {
4798+
err: format!(
4799+
"Channel with id {} is not funded, cannot abandon splice",
4800+
channel_id
4801+
),
4802+
})
4803+
}
4804+
},
4805+
hash_map::Entry::Vacant(_) => Err(APIError::ChannelUnavailable {
4806+
err: format!(
4807+
"Channel with id {} not found for the passed counterparty node_id {}",
4808+
channel_id, counterparty_node_id,
4809+
),
4810+
}),
4811+
}
4812+
}
4813+
47264814
#[rustfmt::skip]
47274815
fn can_forward_htlc_to_outgoing_channel(
47284816
&self, chan: &mut FundedChannel<SP>, msg: &msgs::UpdateAddHTLC, next_packet: &NextPacketDetails

lightning/src/ln/splicing_tests.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -957,3 +957,57 @@ fn fail_splice_on_interactive_tx_error() {
957957
let tx_abort = get_event_msg!(acceptor, MessageSendEvent::SendTxAbort, node_id_initiator);
958958
initiator.node.handle_tx_abort(node_id_acceptor, &tx_abort);
959959
}
960+
961+
#[test]
962+
fn fail_splice_on_tx_abort() {
963+
let chanmon_cfgs = create_chanmon_cfgs(2);
964+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
965+
let config = test_default_anchors_channel_config();
966+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config.clone()), Some(config)]);
967+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
968+
969+
let initiator = &nodes[0];
970+
let acceptor = &nodes[1];
971+
972+
let node_id_initiator = initiator.node.get_our_node_id();
973+
let node_id_acceptor = acceptor.node.get_our_node_id();
974+
975+
let initial_channel_capacity = 100_000;
976+
let (_, _, channel_id, _) =
977+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, initial_channel_capacity, 0);
978+
979+
let coinbase_tx = provide_anchor_reserves(&nodes);
980+
let splice_in_amount = initial_channel_capacity / 2;
981+
let contribution = SpliceContribution::SpliceIn {
982+
value: Amount::from_sat(splice_in_amount),
983+
inputs: vec![FundingTxInput::new_p2wpkh(coinbase_tx, 0).unwrap()],
984+
change_script: Some(nodes[0].wallet_source.get_change_script().unwrap()),
985+
};
986+
987+
// Fail during interactive-tx construction by having the acceptor send tx_abort instead of
988+
// tx_complete.
989+
let _ = complete_splice_handshake(initiator, acceptor, channel_id, contribution.clone());
990+
991+
let tx_add_input =
992+
get_event_msg!(initiator, MessageSendEvent::SendTxAddInput, node_id_acceptor);
993+
acceptor.node.handle_tx_add_input(node_id_initiator, &tx_add_input);
994+
995+
let _tx_complete =
996+
get_event_msg!(acceptor, MessageSendEvent::SendTxComplete, node_id_initiator);
997+
998+
acceptor.node.abandon_splice(&channel_id, &node_id_initiator).unwrap();
999+
let tx_abort = get_event_msg!(acceptor, MessageSendEvent::SendTxAbort, node_id_initiator);
1000+
initiator.node.handle_tx_abort(node_id_acceptor, &tx_abort);
1001+
1002+
let event = get_event!(initiator, Event::SpliceFailed);
1003+
match event {
1004+
Event::SpliceFailed { contributed_inputs, .. } => {
1005+
assert_eq!(contributed_inputs.len(), 1);
1006+
assert_eq!(contributed_inputs[0], contribution.inputs()[0].outpoint());
1007+
},
1008+
_ => panic!("Expected Event::SpliceFailed"),
1009+
}
1010+
1011+
let tx_abort = get_event_msg!(initiator, MessageSendEvent::SendTxAbort, node_id_acceptor);
1012+
acceptor.node.handle_tx_abort(node_id_initiator, &tx_abort);
1013+
}

0 commit comments

Comments
 (0)