Ok(())
}
+ /// Returns transaction if there is pending funding transaction that is yet to broadcast
+ pub fn unbroadcasted_funding(&self) -> Option<Transaction> {
+ if self.channel_state & (ChannelState::FundingCreated as u32) != 0 {
+ self.funding_transaction.clone()
+ } else {
+ None
+ }
+ }
+
/// Returns a HTLCStats about inbound pending htlcs
fn get_inbound_pending_htlc_stats(&self) -> HTLCStats {
let mut stats = HTLCStats {
self.list_channels_with_filter(|&(_, ref channel)| channel.is_live())
}
+ /// Helper function that issues the channel close events
+ fn issue_channel_close_events(&self, channel: &Channel<Signer>, closure_reason: ClosureReason) {
+ let mut pending_events_lock = self.pending_events.lock().unwrap();
+ match channel.unbroadcasted_funding() {
+ Some(transaction) => {
+ pending_events_lock.push(events::Event::DiscardFunding { channel_id: channel.channel_id(), transaction })
+ },
+ None => {},
+ }
+ pending_events_lock.push(events::Event::ChannelClosed { channel_id: channel.channel_id(), reason: closure_reason });
+ }
+
fn close_channel_internal(&self, channel_id: &[u8; 32], target_feerate_sats_per_1000_weight: Option<u32>) -> Result<(), APIError> {
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
msg: channel_update
});
}
- if let Ok(mut pending_events_lock) = self.pending_events.lock() {
- pending_events_lock.push(events::Event::ChannelClosed {
- channel_id: *channel_id,
- reason: ClosureReason::HolderForceClosed
- });
- }
+ self.issue_channel_close_events(&channel, ClosureReason::HolderForceClosed);
}
break Ok(());
},
if let Some(short_id) = chan.get().get_short_channel_id() {
channel_state.short_to_id.remove(&short_id);
}
- let mut pending_events_lock = self.pending_events.lock().unwrap();
if peer_node_id.is_some() {
if let Some(peer_msg) = peer_msg {
- pending_events_lock.push(events::Event::ChannelClosed { channel_id: *channel_id, reason: ClosureReason::CounterpartyForceClosed { peer_msg: peer_msg.to_string() } });
+ self.issue_channel_close_events(chan.get(),ClosureReason::CounterpartyForceClosed { peer_msg: peer_msg.to_string() });
}
} else {
- pending_events_lock.push(events::Event::ChannelClosed { channel_id: *channel_id, reason: ClosureReason::HolderForceClosed });
+ self.issue_channel_close_events(chan.get(),ClosureReason::HolderForceClosed);
}
chan.remove_entry().1
} else {
msg: update
});
}
- self.pending_events.lock().unwrap().push(events::Event::ChannelClosed { channel_id: msg.channel_id, reason: ClosureReason::CooperativeClosure });
+ self.issue_channel_close_events(&chan, ClosureReason::CooperativeClosure);
}
Ok(())
}
msg: update
});
}
- self.pending_events.lock().unwrap().push(events::Event::ChannelClosed { channel_id: chan.channel_id(), reason: ClosureReason::CommitmentTxConfirmed });
+ self.issue_channel_close_events(&chan, ClosureReason::CommitmentTxConfirmed);
pending_msg_events.push(events::MessageSendEvent::HandleError {
node_id: chan.get_counterparty_node_id(),
action: msgs::ErrorAction::SendErrorMessage {
});
}
- if let Ok(mut pending_events_lock) = self.pending_events.lock() {
- pending_events_lock.push(events::Event::ChannelClosed {
- channel_id: *channel_id,
- reason: ClosureReason::CooperativeClosure
- });
- }
+ self.issue_channel_close_events(chan, ClosureReason::CooperativeClosure);
log_info!(self.logger, "Broadcasting {}", log_tx!(tx));
self.tx_broadcaster.broadcast_transaction(&tx);
msg: update
});
}
- self.pending_events.lock().unwrap().push(events::Event::ChannelClosed { channel_id: channel.channel_id(), reason: ClosureReason::CommitmentTxConfirmed });
+ self.issue_channel_close_events(channel, ClosureReason::CommitmentTxConfirmed);
pending_msg_events.push(events::MessageSendEvent::HandleError {
node_id: channel.get_counterparty_node_id(),
action: msgs::ErrorAction::SendErrorMessage { msg: e },
msg: update
});
}
- self.pending_events.lock().unwrap().push(events::Event::ChannelClosed { channel_id: chan.channel_id(), reason: ClosureReason::DisconnectedPeer });
+ self.issue_channel_close_events(chan, ClosureReason::DisconnectedPeer);
false
} else {
true
if let Some(short_id) = chan.get_short_channel_id() {
short_to_id.remove(&short_id);
}
- self.pending_events.lock().unwrap().push(events::Event::ChannelClosed { channel_id: chan.channel_id(), reason: ClosureReason::DisconnectedPeer });
+ self.issue_channel_close_events(chan, ClosureReason::DisconnectedPeer);
return false;
} else {
no_channels_remain = false;
}}
}
-/// Check that a channel's closing channel event has been issued
+/// Check that a channel's closing channel events has been issued
#[macro_export]
macro_rules! check_closed_event {
- ($node: expr, $events: expr, $reason: expr) => {{
+ ($node: expr, $events: expr, $reason: expr) => {
+ check_closed_event!($node, $events, $reason, false);
+ };
+ ($node: expr, $events: expr, $reason: expr, $is_check_discard_funding: expr) => {{
let events = $node.node.get_and_clear_pending_events();
assert_eq!(events.len(), $events);
let expected_reason = $reason;
+ let mut issues_discard_funding = false;
for event in events {
match event {
Event::ChannelClosed { ref reason, .. } => {
assert_eq!(*reason, expected_reason);
},
+ Event::DiscardFunding { .. } => {
+ issues_discard_funding = true;
+ }
_ => panic!("Unexpected event"),
}
}
+ assert_eq!($is_check_discard_funding, issues_discard_funding);
}}
}
let channel_id = ::chain::transaction::OutPoint { txid: funding_created_msg.funding_txid, index: funding_created_msg.funding_output_index }.to_channel_id();
nodes[0].node.handle_error(&nodes[1].node.get_our_node_id(), &msgs::ErrorMessage { channel_id, data: "Hi".to_owned() });
assert!(nodes[0].chain_monitor.added_monitors.lock().unwrap().is_empty());
- check_closed_event!(nodes[0], 1, ClosureReason::CounterpartyForceClosed { peer_msg: "Hi".to_string() });
+ check_closed_event!(nodes[0], 2, ClosureReason::CounterpartyForceClosed { peer_msg: "Hi".to_string() }, true);
}
#[test]
use prelude::*;
use core::time::Duration;
use core::ops::Deref;
+use bitcoin::Transaction;
/// Some information provided on receipt of payment depends on whether the payment received is a
/// spontaneous payment or a "conventional" lightning payment that's paying an invoice.
channel_id: [u8; 32],
/// The reason the channel was closed.
reason: ClosureReason
+ },
+ /// Used to indicate to the user that they can abandon the funding transaction and recycle the
+ /// inputs for another purpose.
+ DiscardFunding {
+ /// The channel_id of the channel which has been closed.
+ channel_id: [u8; 32],
+ /// The full transaction received from the user
+ transaction: Transaction
}
}
(2, reason, required)
});
},
+ &Event::DiscardFunding { ref channel_id, ref transaction } => {
+ 11u8.write(writer)?;
+ write_tlv_fields!(writer, {
+ (0, channel_id, required),
+ (2, transaction, required)
+ })
+ },
// Note that, going forward, all new events must only write data inside of
// `write_tlv_fields`. Versions 0.0.101+ will ignore odd-numbered events that write
// data via `write_tlv_fields`.
if reason.is_none() { return Ok(None); }
Ok(Some(Event::ChannelClosed { channel_id, reason: reason.unwrap() }))
},
+ 11u8 => {
+ let mut channel_id = [0; 32];
+ let mut transaction = Transaction{ version: 2, lock_time: 0, input: Vec::new(), output: Vec::new() };
+ read_tlv_fields!(reader, {
+ (0, channel_id, required),
+ (2, transaction, required),
+ });
+ Ok(Some(Event::DiscardFunding { channel_id, transaction } ))
+ },
// Versions prior to 0.0.100 did not ignore odd types, instead returning InvalidValue.
// Version 0.0.100 failed to properly ignore odd types, possibly resulting in corrupt
// reads.