Merge pull request #853 from TheBlueMatt/2021-03-transaction_unconfirmed
[rust-lightning] / lightning / src / ln / channelmanager.rs
index d2ea7dfea798baea181dec19838cf2b55ccaad22..f9e00bc5d035a3f1742f69db9c55e9ee15d84f7c 100644 (file)
@@ -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<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> 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<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> 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<FN: Fn(&mut Channel<Signer>) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage>>
-                       (&self, height: u32, f: FN) {
+                       (&self, height_opt: Option<u32>, 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<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> 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<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> 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<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> 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<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> 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<Txid> {
+               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