Merge pull request #2863 from benthecarman/breakup-coop-close
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Mon, 5 Feb 2024 23:43:26 +0000 (23:43 +0000)
committerGitHub <noreply@github.com>
Mon, 5 Feb 2024 23:43:26 +0000 (23:43 +0000)
Breakup CooperativeClosure into Local/Remote initiated

lightning/src/events/mod.rs
lightning/src/ln/chanmon_update_fail_tests.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/functional_test_utils.rs
lightning/src/ln/functional_tests.rs
lightning/src/ln/payment_tests.rs
lightning/src/ln/peer_handler.rs
lightning/src/onion_message/messenger.rs
lightning/src/routing/gossip.rs
lightning/src/util/macro_logger.rs

index 270965846e49d3766887e01374da2e3b8ef6b6d9..3bc70014f49aab63105ae94409e94025677ff8ab 100644 (file)
@@ -794,7 +794,7 @@ pub enum Event {
                /// The outgoing channel between the next node and us. This is only `None` for events
                /// generated or serialized by versions prior to 0.0.107.
                next_channel_id: Option<ChannelId>,
-               /// The fee, in milli-satoshis, which was earned as a result of the payment.
+               /// The total fee, in milli-satoshis, which was earned as a result of the payment.
                ///
                /// Note that if we force-closed the channel over which we forwarded an HTLC while the HTLC
                /// was pending, the amount the next hop claimed will have been rounded down to the nearest
@@ -805,15 +805,29 @@ pub enum Event {
                /// If the channel which sent us the payment has been force-closed, we will claim the funds
                /// via an on-chain transaction. In that case we do not yet know the on-chain transaction
                /// fees which we will spend and will instead set this to `None`. It is possible duplicate
-               /// `PaymentForwarded` events are generated for the same payment iff `fee_earned_msat` is
+               /// `PaymentForwarded` events are generated for the same payment iff `total_fee_earned_msat` is
                /// `None`.
-               fee_earned_msat: Option<u64>,
+               total_fee_earned_msat: Option<u64>,
+               /// The share of the total fee, in milli-satoshis, which was withheld in addition to the
+               /// forwarding fee.
+               ///
+               /// This will only be `Some` if we forwarded an intercepted HTLC with less than the
+               /// expected amount. This means our counterparty accepted to receive less than the invoice
+               /// amount, e.g., by claiming the payment featuring a corresponding
+               /// [`PaymentClaimable::counterparty_skimmed_fee_msat`].
+               ///
+               /// Will also always be `None` for events serialized with LDK prior to version 0.0.122.
+               ///
+               /// The caveat described above the `total_fee_earned_msat` field applies here as well.
+               ///
+               /// [`PaymentClaimable::counterparty_skimmed_fee_msat`]: Self::PaymentClaimable::counterparty_skimmed_fee_msat
+               skimmed_fee_msat: Option<u64>,
                /// If this is `true`, the forwarded HTLC was claimed by our counterparty via an on-chain
                /// transaction.
                claim_from_onchain_tx: bool,
                /// The final amount forwarded, in milli-satoshis, after the fee is deducted.
                ///
-               /// The caveat described above the `fee_earned_msat` field applies here as well.
+               /// The caveat described above the `total_fee_earned_msat` field applies here as well.
                outbound_amount_forwarded_msat: Option<u64>,
        },
        /// Used to indicate that a channel with the given `channel_id` is being opened and pending
@@ -842,6 +856,10 @@ pub enum Event {
                counterparty_node_id: PublicKey,
                /// The outpoint of the channel's funding transaction.
                funding_txo: OutPoint,
+               /// The features that this channel will operate with.
+               ///
+               /// Will be `None` for channels created prior to LDK version 0.0.122.
+               channel_type: Option<ChannelTypeFeatures>,
        },
        /// Used to indicate that a channel with the given `channel_id` is ready to
        /// be used. This event is emitted either when the funding transaction has been confirmed
@@ -1094,16 +1112,17 @@ impl Writeable for Event {
                                });
                        }
                        &Event::PaymentForwarded {
-                               fee_earned_msat, prev_channel_id, claim_from_onchain_tx,
-                               next_channel_id, outbound_amount_forwarded_msat
+                               total_fee_earned_msat, prev_channel_id, claim_from_onchain_tx,
+                               next_channel_id, outbound_amount_forwarded_msat, skimmed_fee_msat,
                        } => {
                                7u8.write(writer)?;
                                write_tlv_fields!(writer, {
-                                       (0, fee_earned_msat, option),
+                                       (0, total_fee_earned_msat, option),
                                        (1, prev_channel_id, option),
                                        (2, claim_from_onchain_tx, required),
                                        (3, next_channel_id, option),
                                        (5, outbound_amount_forwarded_msat, option),
+                                       (7, skimmed_fee_msat, option),
                                });
                        },
                        &Event::ChannelClosed { ref channel_id, ref user_channel_id, ref reason,
@@ -1210,10 +1229,14 @@ impl Writeable for Event {
                                        (6, channel_type, required),
                                });
                        },
-                       &Event::ChannelPending { ref channel_id, ref user_channel_id, ref former_temporary_channel_id, ref counterparty_node_id, ref funding_txo } => {
+                       &Event::ChannelPending { ref channel_id, ref user_channel_id,
+                               ref former_temporary_channel_id, ref counterparty_node_id, ref funding_txo,
+                               ref channel_type
+                       } => {
                                31u8.write(writer)?;
                                write_tlv_fields!(writer, {
                                        (0, channel_id, required),
+                                       (1, channel_type, option),
                                        (2, user_channel_id, required),
                                        (4, former_temporary_channel_id, required),
                                        (6, counterparty_node_id, required),
@@ -1395,21 +1418,23 @@ impl MaybeReadable for Event {
                        },
                        7u8 => {
                                let f = || {
-                                       let mut fee_earned_msat = None;
+                                       let mut total_fee_earned_msat = None;
                                        let mut prev_channel_id = None;
                                        let mut claim_from_onchain_tx = false;
                                        let mut next_channel_id = None;
                                        let mut outbound_amount_forwarded_msat = None;
+                                       let mut skimmed_fee_msat = None;
                                        read_tlv_fields!(reader, {
-                                               (0, fee_earned_msat, option),
+                                               (0, total_fee_earned_msat, option),
                                                (1, prev_channel_id, option),
                                                (2, claim_from_onchain_tx, required),
                                                (3, next_channel_id, option),
                                                (5, outbound_amount_forwarded_msat, option),
+                                               (7, skimmed_fee_msat, option),
                                        });
                                        Ok(Some(Event::PaymentForwarded {
-                                               fee_earned_msat, prev_channel_id, claim_from_onchain_tx, next_channel_id,
-                                               outbound_amount_forwarded_msat
+                                               total_fee_earned_msat, prev_channel_id, claim_from_onchain_tx, next_channel_id,
+                                               outbound_amount_forwarded_msat, skimmed_fee_msat,
                                        }))
                                };
                                f()
@@ -1600,8 +1625,10 @@ impl MaybeReadable for Event {
                                        let mut former_temporary_channel_id = None;
                                        let mut counterparty_node_id = RequiredWrapper(None);
                                        let mut funding_txo = RequiredWrapper(None);
+                                       let mut channel_type = None;
                                        read_tlv_fields!(reader, {
                                                (0, channel_id, required),
+                                               (1, channel_type, option),
                                                (2, user_channel_id, required),
                                                (4, former_temporary_channel_id, required),
                                                (6, counterparty_node_id, required),
@@ -1613,7 +1640,8 @@ impl MaybeReadable for Event {
                                                user_channel_id,
                                                former_temporary_channel_id,
                                                counterparty_node_id: counterparty_node_id.0.unwrap(),
-                                               funding_txo: funding_txo.0.unwrap()
+                                               funding_txo: funding_txo.0.unwrap(),
+                                               channel_type,
                                        }))
                                };
                                f()
index 3578a66cb673dca7468ce10a3d4610248f72b059..4d9316db79f8f9157aff3989001a116283e23d82 100644 (file)
@@ -3404,7 +3404,8 @@ fn do_test_reload_mon_update_completion_actions(close_during_reload: bool) {
        let bc_update_id = nodes[1].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&chan_id_bc).unwrap().2;
        let mut events = nodes[1].node.get_and_clear_pending_events();
        assert_eq!(events.len(), if close_during_reload { 2 } else { 1 });
-       expect_payment_forwarded(events.pop().unwrap(), &nodes[1], &nodes[0], &nodes[2], Some(1000), close_during_reload, false);
+       expect_payment_forwarded(events.pop().unwrap(), &nodes[1], &nodes[0], &nodes[2], Some(1000),
+               None, close_during_reload, false);
        if close_during_reload {
                match events[0] {
                        Event::ChannelClosed { .. } => {},
index b57d472be12c80cdcf3112919514fbe4c406a8c3..f9c512d7f84cce37f87363680212e920791f41ae 100644 (file)
@@ -3330,7 +3330,7 @@ impl<SP: Deref> Channel<SP> where
                Err(ChannelError::Close("Remote tried to fulfill/fail an HTLC we couldn't find".to_owned()))
        }
 
-       pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<(HTLCSource, u64), ChannelError> {
+       pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<(HTLCSource, u64, Option<u64>), ChannelError> {
                if !matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
                        return Err(ChannelError::Close("Got fulfill HTLC message when channel was not in an operational state".to_owned()));
                }
@@ -3338,7 +3338,7 @@ impl<SP: Deref> Channel<SP> where
                        return Err(ChannelError::Close("Peer sent update_fulfill_htlc when we needed a channel_reestablish".to_owned()));
                }
 
-               self.mark_outbound_htlc_removed(msg.htlc_id, Some(msg.payment_preimage), None).map(|htlc| (htlc.source.clone(), htlc.amount_msat))
+               self.mark_outbound_htlc_removed(msg.htlc_id, Some(msg.payment_preimage), None).map(|htlc| (htlc.source.clone(), htlc.amount_msat, htlc.skimmed_fee_msat))
        }
 
        pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<(), ChannelError> {
index 57598c6f294423c482082025de13113f24397668..756836f2404d742d2191a8cae3e7d6d4e9e0ed09 100644 (file)
@@ -1636,9 +1636,6 @@ pub struct ChannelDetails {
        pub counterparty: ChannelCounterparty,
        /// The Channel's funding transaction output, if we've negotiated the funding transaction with
        /// our counterparty already.
-       ///
-       /// Note that, if this has been set, `channel_id` for V1-established channels will be equivalent to
-       /// `ChannelId::v1_from_funding_outpoint(funding_txo.unwrap())`.
        pub funding_txo: Option<OutPoint>,
        /// The features which this channel operates with. See individual features for more info.
        ///
@@ -2155,6 +2152,7 @@ macro_rules! emit_channel_pending_event {
                                counterparty_node_id: $channel.context.get_counterparty_node_id(),
                                user_channel_id: $channel.context.get_user_id(),
                                funding_txo: $channel.context.get_funding_txo().unwrap().into_bitcoin_outpoint(),
+                               channel_type: Some($channel.context.get_channel_type().clone()),
                        }, None));
                        $channel.context.set_channel_pending_event_emitted();
                }
@@ -2296,7 +2294,7 @@ macro_rules! handle_new_monitor_update {
                handle_new_monitor_update!($self, $update_res, $chan, _internal,
                        handle_monitor_update_completion!($self, $peer_state_lock, $peer_state, $per_peer_state_lock, $chan))
        };
-       ($self: ident, $funding_txo: expr, $channel_id: expr, $update: expr, $peer_state_lock: expr, $peer_state: expr, $per_peer_state_lock: expr, $chan: expr) => { {
+       ($self: ident, $funding_txo: expr, $update: expr, $peer_state_lock: expr, $peer_state: expr, $per_peer_state_lock: expr, $chan: expr) => { {
                let in_flight_updates = $peer_state.in_flight_monitor_updates.entry($funding_txo)
                        .or_insert_with(Vec::new);
                // During startup, we push monitor updates as background events through to here in
@@ -2753,7 +2751,7 @@ where
 
                                                // Update the monitor with the shutdown script if necessary.
                                                if let Some(monitor_update) = monitor_update_opt.take() {
-                                                       handle_new_monitor_update!(self, funding_txo_opt.unwrap(), *channel_id, monitor_update,
+                                                       handle_new_monitor_update!(self, funding_txo_opt.unwrap(), monitor_update,
                                                                peer_state_lock, peer_state, per_peer_state, chan);
                                                }
                                        } else {
@@ -3414,7 +3412,7 @@ where
                                                        }, onion_packet, None, &self.fee_estimator, &&logger);
                                                match break_chan_phase_entry!(self, send_res, chan_phase_entry) {
                                                        Some(monitor_update) => {
-                                                               match handle_new_monitor_update!(self, funding_txo, channel_id, monitor_update, peer_state_lock, peer_state, per_peer_state, chan) {
+                                                               match handle_new_monitor_update!(self, funding_txo, monitor_update, peer_state_lock, peer_state, per_peer_state, chan) {
                                                                        false => {
                                                                                // Note that MonitorUpdateInProgress here indicates (per function
                                                                                // docs) that we will resend the commitment update once monitor
@@ -4770,7 +4768,7 @@ where
                                                                hash_map::Entry::Occupied(mut chan_phase) => {
                                                                        if let ChannelPhase::Funded(chan) = chan_phase.get_mut() {
                                                                                updated_chan = true;
-                                                                               handle_new_monitor_update!(self, funding_txo, channel_id, update.clone(),
+                                                                               handle_new_monitor_update!(self, funding_txo, update.clone(),
                                                                                        peer_state_lock, peer_state, per_peer_state, chan);
                                                                        } else {
                                                                                debug_assert!(false, "We shouldn't have an update for a non-funded channel");
@@ -5574,7 +5572,7 @@ where
                                                                        peer_state.monitor_update_blocked_actions.entry(chan_id).or_insert(Vec::new()).push(action);
                                                                }
                                                                if !during_init {
-                                                                       handle_new_monitor_update!(self, prev_hop.outpoint, prev_hop.channel_id, monitor_update, peer_state_lock,
+                                                                       handle_new_monitor_update!(self, prev_hop.outpoint, monitor_update, peer_state_lock,
                                                                                peer_state, per_peer_state, chan);
                                                                } else {
                                                                        // If we're running during init we cannot update a monitor directly -
@@ -5690,9 +5688,9 @@ where
        }
 
        fn claim_funds_internal(&self, source: HTLCSource, payment_preimage: PaymentPreimage,
-               forwarded_htlc_value_msat: Option<u64>, from_onchain: bool, startup_replay: bool,
-               next_channel_counterparty_node_id: Option<PublicKey>, next_channel_outpoint: OutPoint,
-               next_channel_id: ChannelId,
+               forwarded_htlc_value_msat: Option<u64>, skimmed_fee_msat: Option<u64>, from_onchain: bool,
+               startup_replay: bool, next_channel_counterparty_node_id: Option<PublicKey>,
+               next_channel_outpoint: OutPoint, next_channel_id: ChannelId,
        ) {
                match source {
                        HTLCSource::OutboundRoute { session_priv, payment_id, path, .. } => {
@@ -5788,18 +5786,21 @@ where
                                                                })
                                                        } else { None }
                                                } else {
-                                                       let fee_earned_msat = if let Some(forwarded_htlc_value) = forwarded_htlc_value_msat {
+                                                       let total_fee_earned_msat = if let Some(forwarded_htlc_value) = forwarded_htlc_value_msat {
                                                                if let Some(claimed_htlc_value) = htlc_claim_value_msat {
                                                                        Some(claimed_htlc_value - forwarded_htlc_value)
                                                                } else { None }
                                                        } else { None };
+                                                       debug_assert!(skimmed_fee_msat <= total_fee_earned_msat,
+                                                               "skimmed_fee_msat must always be included in total_fee_earned_msat");
                                                        Some(MonitorUpdateCompletionAction::EmitEventAndFreeOtherChannel {
                                                                event: events::Event::PaymentForwarded {
-                                                                       fee_earned_msat,
+                                                                       total_fee_earned_msat,
                                                                        claim_from_onchain_tx: from_onchain,
                                                                        prev_channel_id: Some(prev_channel_id),
                                                                        next_channel_id: Some(next_channel_id),
                                                                        outbound_amount_forwarded_msat: forwarded_htlc_value_msat,
+                                                                       skimmed_fee_msat,
                                                                },
                                                                downstream_counterparty_and_funding_outpoint: chan_to_release,
                                                        })
@@ -6570,7 +6571,7 @@ where
                                                }
                                                // Update the monitor with the shutdown script if necessary.
                                                if let Some(monitor_update) = monitor_update_opt {
-                                                       handle_new_monitor_update!(self, funding_txo_opt.unwrap(), chan.context.channel_id(), monitor_update,
+                                                       handle_new_monitor_update!(self, funding_txo_opt.unwrap(), monitor_update,
                                                                peer_state_lock, peer_state, per_peer_state, chan);
                                                }
                                        },
@@ -6739,7 +6740,7 @@ where
 
        fn internal_update_fulfill_htlc(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateFulfillHTLC) -> Result<(), MsgHandleErrInternal> {
                let funding_txo;
-               let (htlc_source, forwarded_htlc_value) = {
+               let (htlc_source, forwarded_htlc_value, skimmed_fee_msat) = {
                        let per_peer_state = self.per_peer_state.read().unwrap();
                        let peer_state_mutex = per_peer_state.get(counterparty_node_id)
                                .ok_or_else(|| {
@@ -6777,8 +6778,11 @@ where
                                hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.channel_id))
                        }
                };
-               self.claim_funds_internal(htlc_source, msg.payment_preimage.clone(), Some(forwarded_htlc_value),
-                       false, false, Some(*counterparty_node_id), funding_txo, msg.channel_id);
+               self.claim_funds_internal(htlc_source, msg.payment_preimage.clone(),
+                       Some(forwarded_htlc_value), skimmed_fee_msat, false, false, Some(*counterparty_node_id),
+                       funding_txo, msg.channel_id
+               );
+
                Ok(())
        }
 
@@ -6852,7 +6856,7 @@ where
                                        let funding_txo = chan.context.get_funding_txo();
                                        let monitor_update_opt = try_chan_phase_entry!(self, chan.commitment_signed(&msg, &&logger), chan_phase_entry);
                                        if let Some(monitor_update) = monitor_update_opt {
-                                               handle_new_monitor_update!(self, funding_txo.unwrap(), chan.context.channel_id(), monitor_update, peer_state_lock,
+                                               handle_new_monitor_update!(self, funding_txo.unwrap(), monitor_update, peer_state_lock,
                                                        peer_state, per_peer_state, chan);
                                        }
                                        Ok(())
@@ -7031,7 +7035,7 @@ where
                                                if let Some(monitor_update) = monitor_update_opt {
                                                        let funding_txo = funding_txo_opt
                                                                .expect("Funding outpoint must have been set for RAA handling to succeed");
-                                                       handle_new_monitor_update!(self, funding_txo, chan.context.channel_id(), monitor_update,
+                                                       handle_new_monitor_update!(self, funding_txo, monitor_update,
                                                                peer_state_lock, peer_state, per_peer_state, chan);
                                                }
                                                htlcs_to_fail
@@ -7276,7 +7280,9 @@ where
                                                let logger = WithContext::from(&self.logger, counterparty_node_id, Some(channel_id));
                                                if let Some(preimage) = htlc_update.payment_preimage {
                                                        log_trace!(logger, "Claiming HTLC with preimage {} from our monitor", preimage);
-                                                       self.claim_funds_internal(htlc_update.source, preimage, htlc_update.htlc_value_satoshis.map(|v| v * 1000), true, false, counterparty_node_id, funding_outpoint, channel_id);
+                                                       self.claim_funds_internal(htlc_update.source, preimage,
+                                                               htlc_update.htlc_value_satoshis.map(|v| v * 1000), None, true,
+                                                               false, counterparty_node_id, funding_outpoint, channel_id);
                                                } else {
                                                        log_trace!(logger, "Failing HTLC with hash {} from our monitor", &htlc_update.payment_hash);
                                                        let receiver = HTLCDestination::NextHopChannel { node_id: counterparty_node_id, channel_id };
@@ -7372,7 +7378,7 @@ where
                                                if let Some(monitor_update) = monitor_opt {
                                                        has_monitor_update = true;
 
-                                                       handle_new_monitor_update!(self, funding_txo.unwrap(), chan.context.channel_id(), monitor_update,
+                                                       handle_new_monitor_update!(self, funding_txo.unwrap(), monitor_update,
                                                                peer_state_lock, peer_state, per_peer_state, chan);
                                                        continue 'peer_loop;
                                                }
@@ -8141,7 +8147,7 @@ where
                                                if let Some((monitor_update, further_update_exists)) = chan.unblock_next_blocked_monitor_update() {
                                                        log_debug!(logger, "Unlocking monitor updating for channel {} and updating monitor",
                                                                channel_id);
-                                                       handle_new_monitor_update!(self, channel_funding_outpoint, channel_id, monitor_update,
+                                                       handle_new_monitor_update!(self, channel_funding_outpoint, monitor_update,
                                                                peer_state_lck, peer_state, per_peer_state, chan);
                                                        if further_update_exists {
                                                                // If there are more `ChannelMonitorUpdate`s to process, restart at the
@@ -9816,7 +9822,7 @@ impl_writeable_tlv_based!(PendingAddHTLCInfo, {
        (2, prev_short_channel_id, required),
        (4, prev_htlc_id, required),
        (6, prev_funding_outpoint, required),
-       // Note that by the time we get past the required read for type 2 above, prev_funding_outpoint will be
+       // Note that by the time we get past the required read for type 6 above, prev_funding_outpoint will be
        // filled in, so we can safely unwrap it here.
        (7, prev_channel_id, (default_value, ChannelId::v1_from_funding_outpoint(prev_funding_outpoint.0.unwrap()))),
 });
@@ -11079,12 +11085,11 @@ where
                                                                Some((blocked_node_id, _blocked_channel_outpoint, blocked_channel_id, blocking_action)), ..
                                                } = action {
                                                        if let Some(blocked_peer_state) = per_peer_state.get(&blocked_node_id) {
-                                                               let channel_id = blocked_channel_id;
                                                                log_trace!(logger,
                                                                        "Holding the next revoke_and_ack from {} until the preimage is durably persisted in the inbound edge's ChannelMonitor",
-                                                                       channel_id);
+                                                                       blocked_channel_id);
                                                                blocked_peer_state.lock().unwrap().actions_blocking_raa_monitor_updates
-                                                                       .entry(*channel_id)
+                                                                       .entry(*blocked_channel_id)
                                                                        .or_insert_with(Vec::new).push(blocking_action.clone());
                                                        } else {
                                                                // If the channel we were blocking has closed, we don't need to
@@ -11168,7 +11173,7 @@ where
                        // We use `downstream_closed` in place of `from_onchain` here just as a guess - we
                        // don't remember in the `ChannelMonitor` where we got a preimage from, but if the
                        // channel is closed we just assume that it probably came from an on-chain claim.
-                       channel_manager.claim_funds_internal(source, preimage, Some(downstream_value),
+                       channel_manager.claim_funds_internal(source, preimage, Some(downstream_value), None,
                                downstream_closed, true, downstream_node_id, downstream_funding, downstream_channel_id);
                }
 
index e7fc68924efbda8209ba103b94d8eb54b932be3b..e53fd6b0c1e61908ab7c8f758c34555852fe6ac6 100644 (file)
@@ -2203,14 +2203,19 @@ macro_rules! expect_payment_path_successful {
 
 pub fn expect_payment_forwarded<CM: AChannelManager, H: NodeHolder<CM=CM>>(
        event: Event, node: &H, prev_node: &H, next_node: &H, expected_fee: Option<u64>,
-       upstream_force_closed: bool, downstream_force_closed: bool
+       expected_extra_fees_msat: Option<u64>, upstream_force_closed: bool,
+       downstream_force_closed: bool
 ) {
        match event {
                Event::PaymentForwarded {
-                       fee_earned_msat, prev_channel_id, claim_from_onchain_tx, next_channel_id,
-                       outbound_amount_forwarded_msat: _
+                       total_fee_earned_msat, prev_channel_id, claim_from_onchain_tx, next_channel_id,
+                       outbound_amount_forwarded_msat: _, skimmed_fee_msat
                } => {
-                       assert_eq!(fee_earned_msat, expected_fee);
+                       assert_eq!(total_fee_earned_msat, expected_fee);
+
+                       // Check that the (knowingly) withheld amount is always less or equal to the expected
+                       // overpaid amount.
+                       assert!(skimmed_fee_msat == expected_extra_fees_msat);
                        if !upstream_force_closed {
                                // Is the event prev_channel_id in one of the channels between the two nodes?
                                assert!(node.node().list_channels().iter().any(|x| x.counterparty.node_id == prev_node.node().get_our_node_id() && x.channel_id == prev_channel_id.unwrap()));
@@ -2226,13 +2231,15 @@ pub fn expect_payment_forwarded<CM: AChannelManager, H: NodeHolder<CM=CM>>(
        }
 }
 
+#[macro_export]
 macro_rules! expect_payment_forwarded {
        ($node: expr, $prev_node: expr, $next_node: expr, $expected_fee: expr, $upstream_force_closed: expr, $downstream_force_closed: expr) => {
                let mut events = $node.node.get_and_clear_pending_events();
                assert_eq!(events.len(), 1);
                $crate::ln::functional_test_utils::expect_payment_forwarded(
-                       events.pop().unwrap(), &$node, &$prev_node, &$next_node, $expected_fee,
-                       $upstream_force_closed, $downstream_force_closed);
+                       events.pop().unwrap(), &$node, &$prev_node, &$next_node, $expected_fee, None,
+                       $upstream_force_closed, $downstream_force_closed
+               );
        }
 }
 
@@ -2552,24 +2559,54 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(
        origin_node: &Node<'a, 'b, 'c>, expected_paths: &[&[&Node<'a, 'b, 'c>]], skip_last: bool,
        our_payment_preimage: PaymentPreimage
 ) -> u64 {
-       let extra_fees = vec![0; expected_paths.len()];
-       do_claim_payment_along_route_with_extra_penultimate_hop_fees(origin_node, expected_paths,
-               &extra_fees[..], skip_last, our_payment_preimage)
-}
-
-pub fn do_claim_payment_along_route_with_extra_penultimate_hop_fees<'a, 'b, 'c>(
-       origin_node: &Node<'a, 'b, 'c>, expected_paths: &[&[&Node<'a, 'b, 'c>]], expected_extra_fees:
-       &[u32], skip_last: bool, our_payment_preimage: PaymentPreimage
-) -> u64 {
-       assert_eq!(expected_paths.len(), expected_extra_fees.len());
        for path in expected_paths.iter() {
                assert_eq!(path.last().unwrap().node.get_our_node_id(), expected_paths[0].last().unwrap().node.get_our_node_id());
        }
        expected_paths[0].last().unwrap().node.claim_funds(our_payment_preimage);
-       pass_claimed_payment_along_route(origin_node, expected_paths, expected_extra_fees, skip_last, our_payment_preimage)
+       pass_claimed_payment_along_route(
+               ClaimAlongRouteArgs::new(origin_node, expected_paths, our_payment_preimage)
+                       .skip_last(skip_last)
+       )
+}
+
+pub struct ClaimAlongRouteArgs<'a, 'b, 'c, 'd> {
+       pub origin_node: &'a Node<'b, 'c, 'd>,
+       pub expected_paths: &'a [&'a [&'a Node<'b, 'c, 'd>]],
+       pub expected_extra_fees: Vec<u32>,
+       pub expected_min_htlc_overpay: Vec<u32>,
+       pub skip_last: bool,
+       pub payment_preimage: PaymentPreimage,
 }
 
-pub fn pass_claimed_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_paths: &[&[&Node<'a, 'b, 'c>]], expected_extra_fees: &[u32], skip_last: bool, our_payment_preimage: PaymentPreimage) -> u64 {
+impl<'a, 'b, 'c, 'd> ClaimAlongRouteArgs<'a, 'b, 'c, 'd> {
+       pub fn new(
+               origin_node: &'a Node<'b, 'c, 'd>, expected_paths: &'a [&'a [&'a Node<'b, 'c, 'd>]],
+               payment_preimage: PaymentPreimage,
+       ) -> Self {
+               Self {
+                       origin_node, expected_paths, expected_extra_fees: vec![0; expected_paths.len()],
+                       expected_min_htlc_overpay: vec![0; expected_paths.len()], skip_last: false, payment_preimage,
+               }
+       }
+       pub fn skip_last(mut self, skip_last: bool) -> Self {
+               self.skip_last = skip_last;
+               self
+       }
+       pub fn with_expected_extra_fees(mut self, extra_fees: Vec<u32>) -> Self {
+               self.expected_extra_fees = extra_fees;
+               self
+       }
+       pub fn with_expected_min_htlc_overpay(mut self, extra_fees: Vec<u32>) -> Self {
+               self.expected_min_htlc_overpay = extra_fees;
+               self
+       }
+}
+
+pub fn pass_claimed_payment_along_route<'a, 'b, 'c, 'd>(args: ClaimAlongRouteArgs) -> u64 {
+       let ClaimAlongRouteArgs {
+               origin_node, expected_paths, expected_extra_fees, expected_min_htlc_overpay, skip_last,
+               payment_preimage: our_payment_preimage
+       } = args;
        let claim_event = expected_paths[0].last().unwrap().node.get_and_clear_pending_events();
        assert_eq!(claim_event.len(), 1);
        match claim_event[0] {
@@ -2666,8 +2703,17 @@ pub fn pass_claimed_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, '
                                                        channel.context().config().forwarding_fee_base_msat
                                                }
                                        };
-                                       if $idx == 1 { fee += expected_extra_fees[i]; }
-                                       expect_payment_forwarded!(*$node, $next_node, $prev_node, Some(fee as u64), false, false);
+
+                                       let mut expected_extra_fee = None;
+                                       if $idx == 1 {
+                                               fee += expected_extra_fees[i];
+                                               fee += expected_min_htlc_overpay[i];
+                                               expected_extra_fee = if expected_extra_fees[i] > 0 { Some(expected_extra_fees[i] as u64) } else { None };
+                                       }
+                                       let mut events = $node.node.get_and_clear_pending_events();
+                                       assert_eq!(events.len(), 1);
+                                       expect_payment_forwarded(events.pop().unwrap(), *$node, $next_node, $prev_node,
+                                               Some(fee as u64), expected_extra_fee, false, false);
                                        expected_total_fee_msat += fee as u64;
                                        check_added_monitors!($node, 1);
                                        let new_next_msgs = if $new_msgs {
index cb5a2df33299f4e8443c39fc20453bc3ddd5ef0d..c83b19e7e571e95569c7e11d1acaaa09a03d65cd 100644 (file)
@@ -2889,8 +2889,10 @@ fn test_htlc_on_chain_success() {
        }
        let chan_id = Some(chan_1.2);
        match forwarded_events[1] {
-               Event::PaymentForwarded { fee_earned_msat, prev_channel_id, claim_from_onchain_tx, next_channel_id, outbound_amount_forwarded_msat } => {
-                       assert_eq!(fee_earned_msat, Some(1000));
+               Event::PaymentForwarded { total_fee_earned_msat, prev_channel_id, claim_from_onchain_tx,
+                       next_channel_id, outbound_amount_forwarded_msat, ..
+               } => {
+                       assert_eq!(total_fee_earned_msat, Some(1000));
                        assert_eq!(prev_channel_id, chan_id);
                        assert_eq!(claim_from_onchain_tx, true);
                        assert_eq!(next_channel_id, Some(chan_2.2));
@@ -2899,8 +2901,10 @@ fn test_htlc_on_chain_success() {
                _ => panic!()
        }
        match forwarded_events[2] {
-               Event::PaymentForwarded { fee_earned_msat, prev_channel_id, claim_from_onchain_tx, next_channel_id, outbound_amount_forwarded_msat } => {
-                       assert_eq!(fee_earned_msat, Some(1000));
+               Event::PaymentForwarded { total_fee_earned_msat, prev_channel_id, claim_from_onchain_tx,
+                       next_channel_id, outbound_amount_forwarded_msat, ..
+               } => {
+                       assert_eq!(total_fee_earned_msat, Some(1000));
                        assert_eq!(prev_channel_id, chan_id);
                        assert_eq!(claim_from_onchain_tx, true);
                        assert_eq!(next_channel_id, Some(chan_2.2));
@@ -4912,8 +4916,10 @@ fn test_onchain_to_onchain_claim() {
                _ => panic!("Unexpected event"),
        }
        match events[1] {
-               Event::PaymentForwarded { fee_earned_msat, prev_channel_id, claim_from_onchain_tx, next_channel_id, outbound_amount_forwarded_msat } => {
-                       assert_eq!(fee_earned_msat, Some(1000));
+               Event::PaymentForwarded { total_fee_earned_msat, prev_channel_id, claim_from_onchain_tx,
+                       next_channel_id, outbound_amount_forwarded_msat, ..
+               } => {
+                       assert_eq!(total_fee_earned_msat, Some(1000));
                        assert_eq!(prev_channel_id, Some(chan_1.2));
                        assert_eq!(claim_from_onchain_tx, true);
                        assert_eq!(next_channel_id, Some(chan_2.2));
index 0db815a708532f590d5d7821d2f0bc156e03ad8f..09c022a4c87b1f3e8d106126fde4fd212c22b75a 100644 (file)
@@ -277,10 +277,12 @@ fn mpp_retry_overpay() {
 
        // Can't use claim_payment_along_route as it doesn't support overpayment, so we break out the
        // individual steps here.
+       nodes[3].node.claim_funds(payment_preimage);
        let extra_fees = vec![0, total_overpaid_amount];
-       let expected_total_fee_msat = do_claim_payment_along_route_with_extra_penultimate_hop_fees(
-               &nodes[0], &[&[&nodes[1], &nodes[3]], &[&nodes[2], &nodes[3]]], &extra_fees[..], false,
-               payment_preimage);
+       let expected_route = &[&[&nodes[1], &nodes[3]][..], &[&nodes[2], &nodes[3]][..]];
+       let args = ClaimAlongRouteArgs::new(&nodes[0], &expected_route[..], payment_preimage)
+               .with_expected_min_htlc_overpay(extra_fees);
+       let expected_total_fee_msat = pass_claimed_payment_along_route(args);
        expect_payment_sent!(&nodes[0], payment_preimage, Some(expected_total_fee_msat));
 }
 
@@ -2155,9 +2157,10 @@ fn do_accept_underpaying_htlcs_config(num_mpp_parts: usize) {
        let mut expected_paths = Vec::new();
        for _ in 0..num_mpp_parts { expected_paths_vecs.push(vec!(&nodes[1], &nodes[2])); }
        for i in 0..num_mpp_parts { expected_paths.push(&expected_paths_vecs[i][..]); }
-       let total_fee_msat = do_claim_payment_along_route_with_extra_penultimate_hop_fees(
-               &nodes[0], &expected_paths[..], &vec![skimmed_fee_msat as u32; num_mpp_parts][..], false,
-               payment_preimage);
+       expected_paths[0].last().unwrap().node.claim_funds(payment_preimage);
+       let args = ClaimAlongRouteArgs::new(&nodes[0], &expected_paths[..], payment_preimage)
+               .with_expected_extra_fees(vec![skimmed_fee_msat as u32; num_mpp_parts]);
+       let total_fee_msat = pass_claimed_payment_along_route(args);
        // The sender doesn't know that the penultimate hop took an extra fee.
        expect_payment_sent(&nodes[0], payment_preimage,
                Some(Some(total_fee_msat - skimmed_fee_msat * num_mpp_parts as u64)), true, true);
@@ -3722,7 +3725,7 @@ fn do_test_custom_tlvs(spontaneous: bool, even_tlvs: bool, known_tlvs: bool) {
        match (known_tlvs, even_tlvs) {
                (true, _) => {
                        nodes[1].node.claim_funds_with_known_custom_tlvs(our_payment_preimage);
-                       let expected_total_fee_msat = pass_claimed_payment_along_route(&nodes[0], &[&[&nodes[1]]], &[0; 1], false, our_payment_preimage);
+                       let expected_total_fee_msat = pass_claimed_payment_along_route(ClaimAlongRouteArgs::new(&nodes[0], &[&[&nodes[1]]], our_payment_preimage));
                        expect_payment_sent!(&nodes[0], our_payment_preimage, Some(expected_total_fee_msat));
                },
                (false, false) => {
index 3b9f9848ec8140273cd0505f5380d4d2b313b6eb..3e07f50b203a0e6c1125ed7e257e376a1d68eb7f 100644 (file)
@@ -24,7 +24,6 @@ use crate::ln::ChannelId;
 use crate::ln::features::{InitFeatures, NodeFeatures};
 use crate::ln::msgs;
 use crate::ln::msgs::{ChannelMessageHandler, LightningError, SocketAddress, OnionMessageHandler, RoutingMessageHandler};
-use crate::util::macro_logger::DebugFundingChannelId;
 use crate::util::ser::{VecWriter, Writeable, Writer};
 use crate::ln::peer_channel_encryptor::{PeerChannelEncryptor, NextNoiseStep, MessageBuf, MSG_BUF_ALLOC_SIZE};
 use crate::ln::wire;
@@ -2007,7 +2006,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
                                                        log_debug!(WithContext::from(&self.logger, Some(*node_id), Some(msg.temporary_channel_id)), "Handling SendFundingCreated event in peer_handler for node {} for channel {} (which becomes {})",
                                                                        log_pubkey!(node_id),
                                                                        &msg.temporary_channel_id,
-                                                                       DebugFundingChannelId(&msg.funding_txid, msg.funding_output_index));
+                                                                       ChannelId::v1_from_funding_txid(msg.funding_txid.as_byte_array(), msg.funding_output_index));
                                                        // TODO: If the peer is gone we should generate a DiscardFunding event
                                                        // indicating to the wallet that they should just throw away this funding transaction
                                                        self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
index 3678dea84d6df869297eb8be87c355055501504b..1c37fc3d71e7c4e309e043b27e5fe0dd51138f27 100644 (file)
@@ -811,8 +811,8 @@ where
                }
        }
 
-       #[cfg(test)]
-       pub(super) fn send_onion_message_using_path<T: OnionMessageContents>(
+       #[cfg(any(test, feature = "_test_utils"))]
+       pub fn send_onion_message_using_path<T: OnionMessageContents>(
                &self, path: OnionMessagePath, contents: T, reply_path: Option<BlindedPath>
        ) -> Result<SendSuccess, SendError> {
                self.enqueue_onion_message(path, contents, reply_path, format_args!(""))
index 9c8fd40af1358f1e1c8ae04646607da68a4e7abe..4c7a3762a278fa1e768af4034de4b5b98f014319 100644 (file)
@@ -1032,13 +1032,13 @@ impl<'a> DirectedChannelInfo<'a> {
        ///
        /// Refers to the `node_id` forwarding the payment to the next hop.
        #[inline]
-       pub(super) fn source(&self) -> &'a NodeId { if self.from_node_one { &self.channel.node_one } else { &self.channel.node_two } }
+       pub fn source(&self) -> &'a NodeId { if self.from_node_one { &self.channel.node_one } else { &self.channel.node_two } }
 
        /// Returns the `node_id` of the target hop.
        ///
        /// Refers to the `node_id` receiving the payment from the previous hop.
        #[inline]
-       pub(super) fn target(&self) -> &'a NodeId { if self.from_node_one { &self.channel.node_two } else { &self.channel.node_one } }
+       pub fn target(&self) -> &'a NodeId { if self.from_node_one { &self.channel.node_two } else { &self.channel.node_one } }
 }
 
 impl<'a> fmt::Debug for DirectedChannelInfo<'a> {
index 55b11604d94dec1e4af4c36eb0804039cb764978..f962251cd65bd7baf072a9bcbfa0d731d4bfec64 100644 (file)
@@ -7,11 +7,9 @@
 // You may not use this file except in accordance with one or both of these
 // licenses.
 
-use crate::chain::transaction::OutPoint;
 use crate::ln::ChannelId;
 use crate::sign::SpendableOutputDescriptor;
 
-use bitcoin::hash_types::Txid;
 use bitcoin::blockdata::transaction::Transaction;
 
 use crate::routing::router::Route;
@@ -39,13 +37,6 @@ macro_rules! log_bytes {
        }
 }
 
-pub(crate) struct DebugFundingChannelId<'a>(pub &'a Txid, pub u16);
-impl<'a> core::fmt::Display for DebugFundingChannelId<'a> {
-       fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
-               ChannelId::v1_from_funding_outpoint(OutPoint { txid: self.0.clone(), index: self.1 }).fmt(f)
-       }
-}
-
 pub(crate) struct DebugFundingInfo<'a>(pub &'a ChannelId);
 impl<'a> core::fmt::Display for DebugFundingInfo<'a> {
        fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {