X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmanager.rs;h=f9e00bc5d035a3f1742f69db9c55e9ee15d84f7c;hb=24351f5868ad8f379ecfd11253d3983305dd424d;hp=d2ea7dfea798baea181dec19838cf2b55ccaad22;hpb=eee1c30ea6592463d41eefad8306223ec5548014;p=rust-lightning diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index d2ea7dfe..f9e00bc5 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -28,7 +28,7 @@ use bitcoin::hashes::hmac::{Hmac, HmacEngine}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::sha256d::Hash as Sha256dHash; use bitcoin::hashes::cmp::fixed_time_eq; -use bitcoin::hash_types::BlockHash; +use bitcoin::hash_types::{BlockHash, Txid}; use bitcoin::secp256k1::key::{SecretKey,PublicKey}; use bitcoin::secp256k1::Secp256k1; @@ -851,6 +851,11 @@ impl ChannelMana } } + /// Gets the current configuration applied to all new channels, as + pub fn get_current_default_configuration(&self) -> &UserConfig { + &self.default_configuration + } + /// Creates a new outbound channel to the given remote node and with the given value. /// /// user_id will be provided back as user_channel_id in FundingGenerationReady events to allow @@ -3353,7 +3358,7 @@ where "Blocks must be disconnected in chain-order - the disconnected block must have the correct height"); *self.last_block_hash.write().unwrap() = header.prev_blockhash; - self.do_chain_event(new_height, |channel| channel.update_best_block(new_height, header.time)); + self.do_chain_event(Some(new_height), |channel| channel.update_best_block(new_height, header.time)); } } @@ -3364,8 +3369,11 @@ impl ChannelMana F::Target: FeeEstimator, L::Target: Logger, { + /// Calls a function which handles an on-chain event (blocks dis/connected, transactions + /// un/confirmed, etc) on each channel, handling any resulting errors or messages generated by + /// the function. fn do_chain_event) -> Result<(Option, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage>> - (&self, height: u32, f: FN) { + (&self, height_opt: Option, f: FN) { // Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called // during initialization prior to the chain_monitor being fully configured in some cases. // See the docs for `ChannelManagerReadArgs` for more. @@ -3424,24 +3432,26 @@ impl ChannelMana true }); - channel_state.claimable_htlcs.retain(|&(ref payment_hash, _), htlcs| { - htlcs.retain(|htlc| { - // If height is approaching the number of blocks we think it takes us to get - // our commitment transaction confirmed before the HTLC expires, plus the - // number of blocks we generally consider it to take to do a commitment update, - // just give up on it and fail the HTLC. - if height >= htlc.cltv_expiry - HTLC_FAIL_BACK_BUFFER { - let mut htlc_msat_height_data = byte_utils::be64_to_array(htlc.value).to_vec(); - htlc_msat_height_data.extend_from_slice(&byte_utils::be32_to_array(height)); - timed_out_htlcs.push((HTLCSource::PreviousHopData(htlc.prev_hop.clone()), payment_hash.clone(), HTLCFailReason::Reason { - failure_code: 0x4000 | 15, - data: htlc_msat_height_data - })); - false - } else { true } + if let Some(height) = height_opt { + channel_state.claimable_htlcs.retain(|&(ref payment_hash, _), htlcs| { + htlcs.retain(|htlc| { + // If height is approaching the number of blocks we think it takes us to get + // our commitment transaction confirmed before the HTLC expires, plus the + // number of blocks we generally consider it to take to do a commitment update, + // just give up on it and fail the HTLC. + if height >= htlc.cltv_expiry - HTLC_FAIL_BACK_BUFFER { + let mut htlc_msat_height_data = byte_utils::be64_to_array(htlc.value).to_vec(); + htlc_msat_height_data.extend_from_slice(&byte_utils::be32_to_array(height)); + timed_out_htlcs.push((HTLCSource::PreviousHopData(htlc.prev_hop.clone()), payment_hash.clone(), HTLCFailReason::Reason { + failure_code: 0x4000 | 15, + data: htlc_msat_height_data + })); + false + } else { true } + }); + !htlcs.is_empty() // Only retain this entry if htlcs has at least one entry. }); - !htlcs.is_empty() // Only retain this entry if htlcs has at least one entry. - }); + } } self.handle_init_event_channel_failures(failed_channels); @@ -3477,7 +3487,7 @@ impl ChannelMana log_trace!(self.logger, "{} transactions included in block {} at height {} provided", txdata.len(), block_hash, height); let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); - self.do_chain_event(height, |channel| channel.transactions_confirmed(&block_hash, height, txdata, &self.logger).map(|a| (a, Vec::new()))); + self.do_chain_event(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, &self.logger).map(|a| (a, Vec::new()))); } /// Updates channel state with the current best blockchain tip. You should attempt to call this @@ -3506,7 +3516,7 @@ impl ChannelMana self.latest_block_height.store(height as usize, Ordering::Release); *self.last_block_hash.write().unwrap() = block_hash; - self.do_chain_event(height, |channel| channel.update_best_block(height, header.time)); + self.do_chain_event(Some(height), |channel| channel.update_best_block(height, header.time)); loop { // Update last_node_announcement_serial to be the max of its current value and the @@ -3522,6 +3532,61 @@ impl ChannelMana } } + /// Gets the set of txids which should be monitored for their confirmation state. + /// + /// If you're providing information about reorganizations via [`transaction_unconfirmed`], this + /// is the set of transactions which you may need to call [`transaction_unconfirmed`] for. + /// + /// This may be useful to poll to determine the set of transactions which must be registered + /// with an Electrum server or for which an Electrum server needs to be polled to determine + /// transaction confirmation state. + /// + /// This may update after any [`transactions_confirmed`] or [`block_connected`] call. + /// + /// Note that this is NOT the set of transactions which must be included in calls to + /// [`transactions_confirmed`] if they are confirmed, but a small subset of it. + /// + /// [`transactions_confirmed`]: Self::transactions_confirmed + /// [`transaction_unconfirmed`]: Self::transaction_unconfirmed + /// [`block_connected`]: chain::Listen::block_connected + pub fn get_relevant_txids(&self) -> Vec { + let channel_state = self.channel_state.lock().unwrap(); + let mut res = Vec::with_capacity(channel_state.short_to_id.len()); + for chan in channel_state.by_id.values() { + if let Some(funding_txo) = chan.get_funding_txo() { + res.push(funding_txo.txid); + } + } + res + } + + /// Marks a transaction as having been reorganized out of the blockchain. + /// + /// If a transaction is included in [`get_relevant_txids`], and is no longer in the main branch + /// of the blockchain, this function should be called to indicate that the transaction should + /// be considered reorganized out. + /// + /// Once this is called, the given transaction will no longer appear on [`get_relevant_txids`], + /// though this may be called repeatedly for a given transaction without issue. + /// + /// Note that if the transaction is confirmed on the main chain in a different block (indicated + /// via a call to [`transactions_confirmed`]), it may re-appear in [`get_relevant_txids`], thus + /// be very wary of race-conditions wherein the final state of a transaction indicated via + /// these APIs is not the same as its state on the blockchain. + /// + /// [`transactions_confirmed`]: Self::transactions_confirmed + /// [`get_relevant_txids`]: Self::get_relevant_txids + pub fn transaction_unconfirmed(&self, txid: &Txid) { + let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); + self.do_chain_event(None, |channel| { + if let Some(funding_txo) = channel.get_funding_txo() { + if funding_txo.txid == *txid { + channel.funding_transaction_unconfirmed().map(|_| (None, Vec::new())) + } else { Ok((None, Vec::new())) } + } else { Ok((None, Vec::new())) } + }); + } + /// Blocks until ChannelManager needs to be persisted or a timeout is reached. It returns a bool /// indicating whether persistence is necessary. Only one listener on /// `await_persistable_update` or `await_persistable_update_timeout` is guaranteed to be woken