fn check_state_for_htlc_msg(&self) -> Result<(), ChannelError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
- return Err(ChannelError::Close("Got HTLC message when channel was not in an operational state".to_owned()));
+ let early_funding_locked_state = ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32;
+ if self.channel_state & early_funding_locked_state != early_funding_locked_state {
+ return Err(ChannelError::Close("Got HTLC message when channel was not in an operational state".to_owned()));
+ }
}
if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
return Err(ChannelError::Close("Peer sent HTLC message when we needed a channel_reestablish".to_owned()));
/// Returns true if this channel is fully established and not known to be closing.
/// Allowed in any state (including after shutdown)
+ #[inline]
pub fn is_usable(&self) -> bool {
let mask = ChannelState::ChannelFunded as u32 | BOTH_SIDES_SHUTDOWN_MASK;
(self.channel_state & mask) == (ChannelState::ChannelFunded as u32) && !self.monitor_pending_funding_locked
/// Returns true if this channel is currently available for use. This is a superset of
/// is_usable() and considers things like the channel being temporarily disabled.
/// Allowed in any state (including after shutdown)
+ #[inline]
pub fn is_live(&self) -> bool {
self.is_usable() && (self.channel_state & (ChannelState::PeerDisconnected as u32) == 0)
}
+ /// Returns true if this channel is currently available for receiving inbound payments *to us*.
+ /// This may be true even if [`is_usable`] (or [`is_live`]) is *not* true, if our counterparty
+ /// is willing to forward payments to us with 0 confirmations on the funding transaction.
+ /// Note that payments received on this channel MUST NOT be forwarded unless we've marked the
+ /// channel trusted or [`is_usable`] is also true.
+ /// Allowed in any state (including after shutdown)
+ pub fn is_receivable(&self) -> bool {
+ let non_live_state_reqd = ChannelState::TheirFundingLocked as u32 | ChannelState::ChannelState::FundingSent as u32;
+ self.is_live() || (
+ (self.channel_state & BOTH_SIDES_SHUTDOWN_MASK) == 0 &&
+ (self.channel_state & ChannelState::PeerDisconnected as u32) == 0 &&
+ (self.channel_state & non_live_state_reqd) == non_live_state_reqd
+ )
+ }
+
/// Returns true if this channel has been marked as awaiting a monitor update to move forward.
/// Allowed in any state (including after shutdown)
pub fn is_awaiting_monitor_update(&self) -> bool {
///
/// This is a strict superset of `is_funding_locked`.
pub is_usable: bool,
+ pub is_receivable: bool,
/// True if this channel is (or will be) publicly-announced.
pub is_public: bool,
}
force_close_spend_delay: channel.get_counterparty_selected_contest_delay(),
is_outbound: channel.is_outbound(),
is_funding_locked: channel.is_usable(),
- is_usable: channel.is_live(),
+ is_outbound_usable: channel.is_live(),
+ is_inbound_usable: channel.is_live(),
is_public: channel.should_announce(),
});
}
self.list_channels_with_filter(|&(_, ref channel)| channel.is_live())
}
+ /// Gets the list of channels on which we can receive a payment to us, in random order. Useful
+ /// to generate a list of route hints when generating an invoice.
+ ///
+ /// These are guaranteed to have their [`ChannelDetails::is_receivable`] value set to true, see the
+ /// documentation for [`ChannelDetails::is_receivable`] for more info on exactly what the criteria
+ /// are.
+ pub fn list_receivable_channels(&self) -> Vec<ChannelDetails> {
+ // Note we use is_live here instead of usable which leads to somewhat confused
+ // internal/external nomenclature, but that's ok cause that's probably what the user
+ // really wanted anyway.
+ self.list_channels_with_filter(|&(_, ref channel)| channel.is_receivable())
+ }
+
/// 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();