X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmanager.rs;h=f9e00bc5d035a3f1742f69db9c55e9ee15d84f7c;hb=24351f5868ad8f379ecfd11253d3983305dd424d;hp=e87b221025f189ade4bff5ebde5af8908dfa62d9;hpb=8088e4ba1505c026ac91f8c1489fb7d53d6b656e;p=rust-lightning diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index e87b2210..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; @@ -338,7 +338,7 @@ pub(super) struct ChannelHolder { } /// Events which we process internally but cannot be procsesed immediately at the generation site -/// for some reason. They are handled in timer_chan_freshness_every_min, so may be processed with +/// for some reason. They are handled in timer_tick_occurred, so may be processed with /// quite some time lag. enum BackgroundEvent { /// Handle a ChannelMonitorUpdate that closes a channel, broadcasting its current latest holder @@ -403,7 +403,7 @@ pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L> = ChannelManage /// ChannelUpdate messages informing peers that the channel is temporarily disabled. To avoid /// spam due to quick disconnection/reconnection, updates are not sent until the channel has been /// offline for a full minute. In order to track this, you must call -/// timer_chan_freshness_every_min roughly once per minute, though it doesn't have to be perfect. +/// timer_tick_occurred roughly once per minute, though it doesn't have to be perfect. /// /// Rather than using a plain ChannelManager, it is preferable to use either a SimpleArcChannelManager /// a SimpleRefChannelManager, for conciseness. See their documentation for more details, but @@ -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 @@ -1959,10 +1964,10 @@ impl ChannelMana events.append(&mut new_events); } - /// Free the background events, generally called from timer_chan_freshness_every_min. + /// Free the background events, generally called from timer_tick_occurred. /// /// Exposed for testing to allow us to process events quickly without generating accidental - /// BroadcastChannelUpdate events in timer_chan_freshness_every_min. + /// BroadcastChannelUpdate events in timer_tick_occurred. /// /// Expects the caller to have a total_consistency_lock read lock. fn process_background_events(&self) { @@ -1991,7 +1996,7 @@ impl ChannelMana /// This method handles all the details, and must be called roughly once per minute. /// /// Note that in some rare cases this may generate a `chain::Watch::update_channel` call. - pub fn timer_chan_freshness_every_min(&self) { + pub fn timer_tick_occurred(&self) { let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); self.process_background_events(); @@ -3274,7 +3279,7 @@ impl ChannelMana // We cannot broadcast our latest local state via monitor update (as // Channel::force_shutdown tries to make us do) as we may still be in initialization, // so we track the update internally and handle it when the user next calls - // timer_chan_freshness_every_min, guaranteeing we're running normally. + // timer_tick_occurred, guaranteeing we're running normally. if let Some((funding_txo, update)) = failure.0.take() { assert_eq!(update.updates.len(), 1); if let ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast } = update.updates[0] { @@ -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 @@ -4480,7 +4545,6 @@ pub mod bench { use chain::chainmonitor::ChainMonitor; use chain::channelmonitor::Persist; use chain::keysinterface::{KeysManager, InMemorySigner}; - use chain::transaction::OutPoint; use ln::channelmanager::{ChainParameters, ChannelManager, PaymentHash, PaymentPreimage}; use ln::features::InitFeatures; use ln::functional_test_utils::*; @@ -4558,14 +4622,13 @@ pub mod bench { tx = Transaction { version: 2, lock_time: 0, input: Vec::new(), output: vec![TxOut { value: 8_000_000, script_pubkey: output_script, }]}; - let funding_outpoint = OutPoint { txid: tx.txid(), index: 0 }; - node_a.funding_transaction_generated(&temporary_channel_id, funding_outpoint); + node_a.funding_transaction_generated(&temporary_channel_id, tx.clone()).unwrap(); } else { panic!(); } node_b.handle_funding_created(&node_a.get_our_node_id(), &get_event_msg!(node_a_holder, MessageSendEvent::SendFundingCreated, node_b.get_our_node_id())); node_a.handle_funding_signed(&node_b.get_our_node_id(), &get_event_msg!(node_b_holder, MessageSendEvent::SendFundingSigned, node_a.get_our_node_id())); - get_event!(node_a_holder, Event::FundingBroadcastSafe); + assert_eq!(&tx_broadcaster.txn_broadcasted.lock().unwrap()[..], &[tx.clone()]); let block = Block { header: BlockHeader { version: 0x20000000, prev_blockhash: genesis_hash, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 },