-impl<ChanSigner: ChannelKeys> ChainListener for ChannelManager<ChanSigner> {
- fn block_connected(&self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) {
- let header_hash = header.bitcoin_hash();
- log_trace!(self, "Block {} at height {} connected with {} txn matched", header_hash, height, txn_matched.len());
- let _ = self.total_consistency_lock.read().unwrap();
- let mut failed_channels = Vec::new();
- {
- let mut channel_lock = self.channel_state.lock().unwrap();
- let channel_state = &mut *channel_lock;
- let short_to_id = &mut channel_state.short_to_id;
- let pending_msg_events = &mut channel_state.pending_msg_events;
- channel_state.by_id.retain(|_, channel| {
- let chan_res = channel.block_connected(header, height, txn_matched, indexes_of_txn_matched);
- if let Ok(Some(funding_locked)) = chan_res {
- pending_msg_events.push(events::MessageSendEvent::SendFundingLocked {
- node_id: channel.get_their_node_id(),
- msg: funding_locked,
- });
- if let Some(announcement_sigs) = self.get_announcement_sigs(channel) {
- pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures {
- node_id: channel.get_their_node_id(),
- msg: announcement_sigs,
- });
- }
- short_to_id.insert(channel.get_short_channel_id().unwrap(), channel.channel_id());
- } else if let Err(e) = chan_res {
- pending_msg_events.push(events::MessageSendEvent::HandleError {
- node_id: channel.get_their_node_id(),
- action: msgs::ErrorAction::SendErrorMessage { msg: e },
- });
- return false;
- }
- if let Some(funding_txo) = channel.get_funding_txo() {
- for tx in txn_matched {
- for inp in tx.input.iter() {
- if inp.previous_output == funding_txo.into_bitcoin_outpoint() {
- log_trace!(self, "Detected channel-closing tx {} spending {}:{}, closing channel {}", tx.txid(), inp.previous_output.txid, inp.previous_output.vout, log_bytes!(channel.channel_id()));
- if let Some(short_id) = channel.get_short_channel_id() {
- short_to_id.remove(&short_id);
- }
- // It looks like our counterparty went on-chain. We go ahead and
- // broadcast our latest local state as well here, just in case its
- // some kind of SPV attack, though we expect these to be dropped.
- failed_channels.push(channel.force_shutdown());
- if let Ok(update) = self.get_channel_update(&channel) {
- pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
- msg: update
- });
- }
- return false;
- }
- }
- }
- }
- if channel.is_funding_initiated() && channel.channel_monitor().would_broadcast_at_height(height) {
- if let Some(short_id) = channel.get_short_channel_id() {
- short_to_id.remove(&short_id);
- }
- failed_channels.push(channel.force_shutdown());
- // If would_broadcast_at_height() is true, the channel_monitor will broadcast
- // the latest local tx for us, so we should skip that here (it doesn't really
- // hurt anything, but does make tests a bit simpler).
- failed_channels.last_mut().unwrap().0 = Vec::new();
- if let Ok(update) = self.get_channel_update(&channel) {
- pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
- msg: update
- });
+ /// Gets a payment secret and payment hash for use in an invoice given to a third party wishing
+ /// to pay us.
+ ///
+ /// This differs from [`create_inbound_payment_for_hash`] only in that it generates the
+ /// [`PaymentHash`] and [`PaymentPreimage`] for you, returning the first and storing the second.
+ ///
+ /// The [`PaymentPreimage`] will ultimately be returned to you in the [`PaymentReceived`], which
+ /// will have the [`PaymentReceived::payment_preimage`] field filled in. That should then be
+ /// passed directly to [`claim_funds`].
+ ///
+ /// See [`create_inbound_payment_for_hash`] for detailed documentation on behavior and requirements.
+ ///
+ /// [`claim_funds`]: Self::claim_funds
+ /// [`PaymentReceived`]: events::Event::PaymentReceived
+ /// [`PaymentReceived::payment_preimage`]: events::Event::PaymentReceived::payment_preimage
+ /// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash
+ pub fn create_inbound_payment(&self, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32, user_payment_id: u64) -> (PaymentHash, PaymentSecret) {
+ let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes());
+ let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
+
+ (payment_hash,
+ self.set_payment_hash_secret_map(payment_hash, Some(payment_preimage), min_value_msat, invoice_expiry_delta_secs, user_payment_id)
+ .expect("RNG Generated Duplicate PaymentHash"))
+ }
+
+ /// Gets a [`PaymentSecret`] for a given [`PaymentHash`], for which the payment preimage is
+ /// stored external to LDK.
+ ///
+ /// A [`PaymentReceived`] event will only be generated if the [`PaymentSecret`] matches a
+ /// payment secret fetched via this method or [`create_inbound_payment`], and which is at least
+ /// the `min_value_msat` provided here, if one is provided.
+ ///
+ /// The [`PaymentHash`] (and corresponding [`PaymentPreimage`]) must be globally unique. This
+ /// method may return an Err if another payment with the same payment_hash is still pending.
+ ///
+ /// `user_payment_id` will be provided back in [`PaymentReceived::user_payment_id`] events to
+ /// allow tracking of which events correspond with which calls to this and
+ /// [`create_inbound_payment`]. `user_payment_id` has no meaning inside of LDK, it is simply
+ /// copied to events and otherwise ignored. It may be used to correlate PaymentReceived events
+ /// with invoice metadata stored elsewhere.
+ ///
+ /// `min_value_msat` should be set if the invoice being generated contains a value. Any payment
+ /// received for the returned [`PaymentHash`] will be required to be at least `min_value_msat`
+ /// before a [`PaymentReceived`] event will be generated, ensuring that we do not provide the
+ /// sender "proof-of-payment" unless they have paid the required amount.
+ ///
+ /// `invoice_expiry_delta_secs` describes the number of seconds that the invoice is valid for
+ /// in excess of the current time. This should roughly match the expiry time set in the invoice.
+ /// After this many seconds, we will remove the inbound payment, resulting in any attempts to
+ /// pay the invoice failing. The BOLT spec suggests 7,200 secs as a default validity time for
+ /// invoices when no timeout is set.
+ ///
+ /// Note that we use block header time to time-out pending inbound payments (with some margin
+ /// to compensate for the inaccuracy of block header timestamps). Thus, in practice we will
+ /// accept a payment and generate a [`PaymentReceived`] event for some time after the expiry.
+ /// If you need exact expiry semantics, you should enforce them upon receipt of
+ /// [`PaymentReceived`].
+ ///
+ /// May panic if `invoice_expiry_delta_secs` is greater than one year.
+ ///
+ /// Note that invoices generated for inbound payments should have their `min_final_cltv_expiry`
+ /// set to at least [`MIN_FINAL_CLTV_EXPIRY`].
+ ///
+ /// [`create_inbound_payment`]: Self::create_inbound_payment
+ /// [`PaymentReceived`]: events::Event::PaymentReceived
+ /// [`PaymentReceived::user_payment_id`]: events::Event::PaymentReceived::user_payment_id
+ pub fn create_inbound_payment_for_hash(&self, payment_hash: PaymentHash, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32, user_payment_id: u64) -> Result<PaymentSecret, APIError> {
+ self.set_payment_hash_secret_map(payment_hash, None, min_value_msat, invoice_expiry_delta_secs, user_payment_id)
+ }
+}
+
+impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> MessageSendEventsProvider for ChannelManager<Signer, M, T, K, F, L>
+ where M::Target: chain::Watch<Signer>,
+ T::Target: BroadcasterInterface,
+ K::Target: KeysInterface<Signer = Signer>,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+{
+ fn get_and_clear_pending_msg_events(&self) -> Vec<MessageSendEvent> {
+ //TODO: This behavior should be documented. It's non-intuitive that we query
+ // ChannelMonitors when clearing other events.
+ self.process_pending_monitor_events();
+
+ let mut ret = Vec::new();
+ let mut channel_state = self.channel_state.lock().unwrap();
+ mem::swap(&mut ret, &mut channel_state.pending_msg_events);
+ ret
+ }
+}
+
+impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> EventsProvider for ChannelManager<Signer, M, T, K, F, L>
+ where M::Target: chain::Watch<Signer>,
+ T::Target: BroadcasterInterface,
+ K::Target: KeysInterface<Signer = Signer>,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+{
+ fn get_and_clear_pending_events(&self) -> Vec<Event> {
+ //TODO: This behavior should be documented. It's non-intuitive that we query
+ // ChannelMonitors when clearing other events.
+ self.process_pending_monitor_events();
+
+ let mut ret = Vec::new();
+ let mut pending_events = self.pending_events.lock().unwrap();
+ mem::swap(&mut ret, &mut *pending_events);
+ ret
+ }
+}
+
+impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> chain::Listen for ChannelManager<Signer, M, T, K, F, L>
+where
+ M::Target: chain::Watch<Signer>,
+ T::Target: BroadcasterInterface,
+ K::Target: KeysInterface<Signer = Signer>,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+{
+ fn block_connected(&self, block: &Block, height: u32) {
+ {
+ let best_block = self.best_block.read().unwrap();
+ assert_eq!(best_block.block_hash(), block.header.prev_blockhash,
+ "Blocks must be connected in chain-order - the connected header must build on the last connected header");
+ assert_eq!(best_block.height(), height - 1,
+ "Blocks must be connected in chain-order - the connected block height must be one greater than the previous height");
+ }
+
+ let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
+ self.transactions_confirmed(&block.header, &txdata, height);
+ self.best_block_updated(&block.header, height);
+ }
+
+ fn block_disconnected(&self, header: &BlockHeader, height: u32) {
+ let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
+ let new_height = height - 1;
+ {
+ let mut best_block = self.best_block.write().unwrap();
+ assert_eq!(best_block.block_hash(), header.block_hash(),
+ "Blocks must be disconnected in chain-order - the disconnected header must be the last connected header");
+ assert_eq!(best_block.height(), height,
+ "Blocks must be disconnected in chain-order - the disconnected block must have the correct height");
+ *best_block = BestBlock::new(header.prev_blockhash, new_height)
+ }
+
+ self.do_chain_event(Some(new_height), |channel| channel.best_block_updated(new_height, header.time));
+ }
+}
+
+impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> chain::Confirm for ChannelManager<Signer, M, T, K, F, L>
+where
+ M::Target: chain::Watch<Signer>,
+ T::Target: BroadcasterInterface,
+ K::Target: KeysInterface<Signer = Signer>,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+{
+ fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) {
+ // 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.
+
+ let block_hash = header.block_hash();
+ 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(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, &self.logger).map(|a| (a, Vec::new())));
+ }
+
+ fn best_block_updated(&self, header: &BlockHeader, height: u32) {
+ // 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.
+
+ let block_hash = header.block_hash();
+ log_trace!(self.logger, "New best block: {} at height {}", block_hash, height);
+
+ let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
+
+ *self.best_block.write().unwrap() = BestBlock::new(block_hash, height);
+
+ self.do_chain_event(Some(height), |channel| channel.best_block_updated(height, header.time));
+
+ macro_rules! max_time {
+ ($timestamp: expr) => {
+ loop {
+ // Update $timestamp to be the max of its current value and the block
+ // timestamp. This should keep us close to the current time without relying on
+ // having an explicit local time source.
+ // Just in case we end up in a race, we loop until we either successfully
+ // update $timestamp or decide we don't need to.
+ let old_serial = $timestamp.load(Ordering::Acquire);
+ if old_serial >= header.time as usize { break; }
+ if $timestamp.compare_exchange(old_serial, header.time as usize, Ordering::AcqRel, Ordering::Relaxed).is_ok() {
+ break;