X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannel.rs;h=fd0d94d3eb6381fb97dadcd49184d554c42aa94a;hb=7cfafc98ba2429c6505ad11d9296e1ffe35cf60f;hp=7379c7128e182ee55617fd5cd9fe5491c52ad9a5;hpb=c5c5f3fea2012dc53a1974f7ad6c7825b1e42d37;p=rust-lightning diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 7379c712..fd0d94d3 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -250,38 +250,38 @@ enum HTLCUpdateAwaitingACK { } /// There are a few "states" and then a number of flags which can be applied: -/// We first move through init with OurInitSent -> TheirInitSent -> FundingCreated -> FundingSent. -/// TheirChannelReady and OurChannelReady then get set on FundingSent, and when both are set we -/// move on to ChannelReady. -/// Note that PeerDisconnected can be set on both ChannelReady and FundingSent. -/// ChannelReady can then get all remaining flags set on it, until we finish shutdown, then we -/// move on to ShutdownComplete, at which point most calls into this channel are disallowed. +/// We first move through init with `OurInitSent` -> `TheirInitSent` -> `FundingCreated` -> `FundingSent`. +/// `TheirChannelReady` and `OurChannelReady` then get set on `FundingSent`, and when both are set we +/// move on to `ChannelReady`. +/// Note that `PeerDisconnected` can be set on both `ChannelReady` and `FundingSent`. +/// `ChannelReady` can then get all remaining flags set on it, until we finish shutdown, then we +/// move on to `ShutdownComplete`, at which point most calls into this channel are disallowed. enum ChannelState { /// Implies we have (or are prepared to) send our open_channel/accept_channel message OurInitSent = 1 << 0, - /// Implies we have received their open_channel/accept_channel message + /// Implies we have received their `open_channel`/`accept_channel` message TheirInitSent = 1 << 1, - /// We have sent funding_created and are awaiting a funding_signed to advance to FundingSent. - /// Note that this is nonsense for an inbound channel as we immediately generate funding_signed - /// upon receipt of funding_created, so simply skip this state. + /// We have sent `funding_created` and are awaiting a `funding_signed` to advance to `FundingSent`. + /// Note that this is nonsense for an inbound channel as we immediately generate `funding_signed` + /// upon receipt of `funding_created`, so simply skip this state. FundingCreated = 4, - /// Set when we have received/sent funding_created and funding_signed and are thus now waiting - /// on the funding transaction to confirm. The ChannelReady flags are set to indicate when we + /// Set when we have received/sent `funding_created` and `funding_signed` and are thus now waiting + /// on the funding transaction to confirm. The `ChannelReady` flags are set to indicate when we /// and our counterparty consider the funding transaction confirmed. FundingSent = 8, - /// Flag which can be set on FundingSent to indicate they sent us a channel_ready message. - /// Once both TheirChannelReady and OurChannelReady are set, state moves on to ChannelReady. + /// Flag which can be set on `FundingSent` to indicate they sent us a `channel_ready` message. + /// Once both `TheirChannelReady` and `OurChannelReady` are set, state moves on to `ChannelReady`. TheirChannelReady = 1 << 4, - /// Flag which can be set on FundingSent to indicate we sent them a channel_ready message. - /// Once both TheirChannelReady and OurChannelReady are set, state moves on to ChannelReady. + /// Flag which can be set on `FundingSent` to indicate we sent them a `channel_ready` message. + /// Once both `TheirChannelReady` and `OurChannelReady` are set, state moves on to `ChannelReady`. OurChannelReady = 1 << 5, ChannelReady = 64, - /// Flag which is set on ChannelReady and FundingSent indicating remote side is considered - /// "disconnected" and no updates are allowed until after we've done a channel_reestablish + /// Flag which is set on `ChannelReady` and `FundingSent` indicating remote side is considered + /// "disconnected" and no updates are allowed until after we've done a `channel_reestablish` /// dance. PeerDisconnected = 1 << 7, - /// Flag which is set on ChannelReady, FundingCreated, and FundingSent indicating the user has - /// told us a ChannelMonitor update is pending async persistence somewhere and we should pause + /// Flag which is set on `ChannelReady`, FundingCreated, and `FundingSent` indicating the user has + /// told us a `ChannelMonitor` update is pending async persistence somewhere and we should pause /// sending any outbound messages until they've managed to finish. MonitorUpdateInProgress = 1 << 8, /// Flag which implies that we have sent a commitment_signed but are awaiting the responding @@ -289,13 +289,13 @@ enum ChannelState { /// messages as then we will be unable to determine which HTLCs they included in their /// revoke_and_ack implicit ACK, so instead we have to hold them away temporarily to be sent /// later. - /// Flag is set on ChannelReady. + /// Flag is set on `ChannelReady`. AwaitingRemoteRevoke = 1 << 9, - /// Flag which is set on ChannelReady or FundingSent after receiving a shutdown message from + /// Flag which is set on `ChannelReady` or `FundingSent` after receiving a shutdown message from /// the remote end. If set, they may not add any new HTLCs to the channel, and we are expected /// to respond with our own shutdown message when possible. RemoteShutdownSent = 1 << 10, - /// Flag which is set on ChannelReady or FundingSent after sending a shutdown message. At this + /// Flag which is set on `ChannelReady` or `FundingSent` after sending a shutdown message. At this /// point, we may not add any new HTLCs to the channel. LocalShutdownSent = 1 << 11, /// We've successfully negotiated a closing_signed dance. At this point ChannelManager is about @@ -590,6 +590,11 @@ pub(crate) const EXPIRE_PREV_CONFIG_TICKS: usize = 5; /// See [`ChannelContext::sent_message_awaiting_response`] for more information. pub(crate) const DISCONNECT_PEER_AWAITING_RESPONSE_TICKS: usize = 2; +/// The number of ticks that may elapse while we're waiting for an unfunded outbound/inbound channel +/// to be promoted to a [`Channel`] since the unfunded channel was created. An unfunded channel +/// exceeding this age limit will be force-closed and purged from memory. +pub(crate) const UNFUNDED_CHANNEL_AGE_LIMIT_TICKS: usize = 60; + struct PendingChannelMonitorUpdate { update: ChannelMonitorUpdate, } @@ -598,6 +603,28 @@ impl_writeable_tlv_based!(PendingChannelMonitorUpdate, { (0, update, required), }); +/// Contains all state common to unfunded inbound/outbound channels. +pub(super) struct UnfundedChannelContext { + /// A counter tracking how many ticks have elapsed since this unfunded channel was + /// created. If this unfunded channel reaches peer has yet to respond after reaching + /// `UNFUNDED_CHANNEL_AGE_LIMIT_TICKS`, it will be force-closed and purged from memory. + /// + /// This is so that we don't keep channels around that haven't progressed to a funded state + /// in a timely manner. + unfunded_channel_age_ticks: usize, +} + +impl UnfundedChannelContext { + /// Determines whether we should force-close and purge this unfunded channel from memory due to it + /// having reached the unfunded channel age limit. + /// + /// This should be called on every [`super::channelmanager::ChannelManager::timer_tick_occurred`]. + pub fn should_expire_unfunded_channel(&mut self) -> bool { + self.unfunded_channel_age_ticks += 1; + self.unfunded_channel_age_ticks >= UNFUNDED_CHANNEL_AGE_LIMIT_TICKS + } +} + /// Contains everything about the channel including state, and various flags. pub(super) struct ChannelContext { config: LegacyChannelConfig, @@ -970,9 +997,9 @@ impl ChannelContext { &self.channel_type } - /// Guaranteed to be Some after both ChannelReady messages have been exchanged (and, thus, - /// is_usable() returns true). - /// Allowed in any state (including after shutdown) + /// Gets the channel's `short_channel_id`. + /// + /// Will return `None` if the channel hasn't been confirmed yet. pub fn get_short_channel_id(&self) -> Option { self.short_channel_id } @@ -995,7 +1022,7 @@ impl ChannelContext { } /// Returns the funding_txo we either got from our peer, or were given by - /// get_outbound_funding_created. + /// get_funding_created. pub fn get_funding_txo(&self) -> Option { self.channel_transaction_parameters.funding_outpoint } @@ -1440,7 +1467,7 @@ impl ChannelContext { #[inline] /// Creates a set of keys for build_commitment_transaction to generate a transaction which we /// will sign and send to our counterparty. - /// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created) + /// If an Err is returned, it is a ChannelError::Close (for get_funding_created) fn build_remote_transaction_keys(&self) -> TxCreationKeys { //TODO: Ensure that the payment_key derived here ends up in the library users' wallet as we //may see payments to it! @@ -2026,7 +2053,7 @@ fn commit_tx_fee_msat(feerate_per_kw: u32, num_htlcs: usize, channel_type_featur // TODO: We should refactor this to be an Inbound/OutboundChannel until initial setup handshaking // has been completed, and then turn into a Channel to get compiler-time enforcement of things like -// calling channel_id() before we're set up or things like get_outbound_funding_signed on an +// calling channel_id() before we're set up or things like get_funding_signed on an // inbound channel. // // Holder designates channel data owned for the benefit of the user client. @@ -4842,7 +4869,7 @@ impl Channel { // something in the handler for the message that prompted this message): /// Gets an UnsignedChannelAnnouncement for this channel. The channel must be publicly - /// announceable and available for use (have exchanged ChannelReady messages in both + /// announceable and available for use (have exchanged [`ChannelReady`] messages in both /// directions). Should be used for both broadcasted announcements and in response to an /// AnnouncementSignatures message from the remote peer. /// @@ -4850,6 +4877,8 @@ impl Channel { /// closing). /// /// This will only return ChannelError::Ignore upon failure. + /// + /// [`ChannelReady`]: crate::ln::msgs::ChannelReady fn get_channel_announcement( &self, node_signer: &NS, chain_hash: BlockHash, user_config: &UserConfig, ) -> Result where NS::Target: NodeSigner { @@ -4860,6 +4889,8 @@ impl Channel { return Err(ChannelError::Ignore("Cannot get a ChannelAnnouncement if the channel is not currently usable".to_owned())); } + let short_channel_id = self.context.get_short_channel_id() + .ok_or(ChannelError::Ignore("Cannot get a ChannelAnnouncement if the channel has not been confirmed yet".to_owned()))?; let node_id = NodeId::from_pubkey(&node_signer.get_node_id(Recipient::Node) .map_err(|_| ChannelError::Ignore("Failed to retrieve own public key".to_owned()))?); let counterparty_node_id = NodeId::from_pubkey(&self.context.get_counterparty_node_id()); @@ -4868,7 +4899,7 @@ impl Channel { let msg = msgs::UnsignedChannelAnnouncement { features: channelmanager::provided_channel_features(&user_config), chain_hash, - short_channel_id: self.context.get_short_channel_id().unwrap(), + short_channel_id, node_id_1: if were_node_one { node_id } else { counterparty_node_id }, node_id_2: if were_node_one { counterparty_node_id } else { node_id }, bitcoin_key_1: NodeId::from_pubkey(if were_node_one { &self.context.get_holder_pubkeys().funding_pubkey } else { self.context.counterparty_funding_pubkey() }), @@ -4926,11 +4957,16 @@ impl Channel { }, Ok(v) => v }; + let short_channel_id = match self.context.get_short_channel_id() { + Some(scid) => scid, + None => return None, + }; + self.context.announcement_sigs_state = AnnouncementSigsState::MessageSent; Some(msgs::AnnouncementSignatures { channel_id: self.context.channel_id(), - short_channel_id: self.context.get_short_channel_id().unwrap(), + short_channel_id, node_signature: our_node_sig, bitcoin_signature: our_bitcoin_sig, }) @@ -5477,6 +5513,7 @@ impl Channel { /// A not-yet-funded outbound (from holder) channel using V1 channel establishment. pub(super) struct OutboundV1Channel { pub context: ChannelContext, + pub unfunded_context: UnfundedChannelContext, } impl OutboundV1Channel { @@ -5678,12 +5715,13 @@ impl OutboundV1Channel { channel_keys_id, blocked_monitor_updates: Vec::new(), - } + }, + unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 } }) } - /// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created) - fn get_outbound_funding_created_signature(&mut self, logger: &L) -> Result where L::Target: Logger { + /// If an Err is returned, it is a ChannelError::Close (for get_funding_created) + fn get_funding_created_signature(&mut self, logger: &L) -> Result where L::Target: Logger { let counterparty_keys = self.context.build_remote_transaction_keys(); let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx; Ok(self.context.holder_signer.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.context.secp_ctx) @@ -5697,7 +5735,7 @@ impl OutboundV1Channel { /// Note that channel_id changes during this call! /// Do NOT broadcast the funding transaction until after a successful funding_signed call! /// If an Err is returned, it is a ChannelError::Close. - pub fn get_outbound_funding_created(mut self, funding_transaction: Transaction, funding_txo: OutPoint, logger: &L) + pub fn get_funding_created(mut self, funding_transaction: Transaction, funding_txo: OutPoint, logger: &L) -> Result<(Channel, msgs::FundingCreated), (Self, ChannelError)> where L::Target: Logger { if !self.context.is_outbound() { panic!("Tried to create outbound funding_created message on an inbound channel!"); @@ -5714,7 +5752,7 @@ impl OutboundV1Channel { self.context.channel_transaction_parameters.funding_outpoint = Some(funding_txo); self.context.holder_signer.provide_channel_parameters(&self.context.channel_transaction_parameters); - let signature = match self.get_outbound_funding_created_signature(logger) { + let signature = match self.get_funding_created_signature(logger) { Ok(res) => res, Err(e) => { log_error!(logger, "Got bad signatures: {:?}!", e); @@ -5983,6 +6021,7 @@ impl OutboundV1Channel { /// A not-yet-funded inbound (from counterparty) channel using V1 channel establishment. pub(super) struct InboundV1Channel { pub context: ChannelContext, + pub unfunded_context: UnfundedChannelContext, } impl InboundV1Channel { @@ -6310,7 +6349,8 @@ impl InboundV1Channel { channel_keys_id, blocked_monitor_updates: Vec::new(), - } + }, + unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 } }; Ok(chan) @@ -7598,7 +7638,7 @@ mod tests { value: 10000000, script_pubkey: output_script.clone(), }]}; let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 }; - let (mut node_a_chan, funding_created_msg) = node_a_chan.get_outbound_funding_created(tx.clone(), funding_outpoint, &&logger).map_err(|_| ()).unwrap(); + let (mut node_a_chan, funding_created_msg) = node_a_chan.get_funding_created(tx.clone(), funding_outpoint, &&logger).map_err(|_| ()).unwrap(); let (_, funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg, best_block, &&keys_provider, &&logger).map_err(|_| ()).unwrap(); // Node B --> Node A: funding signed @@ -7725,7 +7765,7 @@ mod tests { value: 10000000, script_pubkey: output_script.clone(), }]}; let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 }; - let (mut node_a_chan, funding_created_msg) = node_a_chan.get_outbound_funding_created(tx.clone(), funding_outpoint, &&logger).map_err(|_| ()).unwrap(); + let (mut node_a_chan, funding_created_msg) = node_a_chan.get_funding_created(tx.clone(), funding_outpoint, &&logger).map_err(|_| ()).unwrap(); let (mut node_b_chan, funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg, best_block, &&keys_provider, &&logger).map_err(|_| ()).unwrap(); // Node B --> Node A: funding signed @@ -7913,7 +7953,7 @@ mod tests { value: 10000000, script_pubkey: output_script.clone(), }]}; let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 }; - let (mut node_a_chan, funding_created_msg) = node_a_chan.get_outbound_funding_created(tx.clone(), funding_outpoint, &&logger).map_err(|_| ()).unwrap(); + let (mut node_a_chan, funding_created_msg) = node_a_chan.get_funding_created(tx.clone(), funding_outpoint, &&logger).map_err(|_| ()).unwrap(); let (_, funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg, best_block, &&keys_provider, &&logger).map_err(|_| ()).unwrap(); // Node B --> Node A: funding signed