Skip to content

Commit 6029b1c

Browse files
Account for Path::blinded_tail in channelmanager+outbound_payment
1 parent 5e69575 commit 6029b1c

File tree

3 files changed

+51
-43
lines changed

3 files changed

+51
-43
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, No
4545
#[cfg(any(feature = "_test_utils", test))]
4646
use crate::ln::features::InvoiceFeatures;
4747
use crate::routing::gossip::NetworkGraph;
48-
use crate::routing::router::{BlindedTail, DefaultRouter, InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters, RoutePath, Router};
48+
use crate::routing::router::{BlindedTail, DefaultRouter, InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters, Router};
4949
use crate::routing::scoring::ProbabilisticScorer;
5050
use crate::ln::msgs;
5151
use crate::ln::onion_utils;
@@ -2531,7 +2531,7 @@ where
25312531
// The top-level caller should hold the total_consistency_lock read lock.
25322532
debug_assert!(self.total_consistency_lock.try_write().is_err());
25332533

2534-
log_trace!(self.logger, "Attempting to send payment for path with next hop {}", path.hops.first().unwrap().short_channel_id);
2534+
log_trace!(self.logger, "Attempting to send payment for path with next hop {}", path.first_hop_scid());
25352535
let prng_seed = self.entropy_source.get_secure_random_bytes();
25362536
let session_priv = SecretKey::from_slice(&session_priv_bytes[..]).expect("RNG is busted");
25372537

@@ -2544,7 +2544,7 @@ where
25442544
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, payment_hash);
25452545

25462546
let err: Result<(), _> = loop {
2547-
let (counterparty_node_id, id) = match self.short_to_chan_info.read().unwrap().get(&path.hops.first().unwrap().short_channel_id) {
2547+
let (counterparty_node_id, id) = match self.short_to_chan_info.read().unwrap().get(&path.first_hop_scid()) {
25482548
None => return Err(APIError::ChannelUnavailable{err: "No channel available with first hop!".to_owned()}),
25492549
Some((cp_id, chan_id)) => (cp_id.clone(), chan_id.clone()),
25502550
};
@@ -2595,7 +2595,7 @@ where
25952595
return Ok(());
25962596
};
25972597

2598-
match handle_error!(self, err, path.hops.first().unwrap().pubkey) {
2598+
match handle_error!(self, err, path.first_hop_node_id()) {
25992599
Ok(_) => unreachable!(),
26002600
Err(e) => {
26012601
Err(APIError::ChannelUnavailable { err: e.err })
@@ -7588,12 +7588,12 @@ where
75887588
if id_to_peer.get(&monitor.get_funding_txo().0.to_channel_id()).is_none() {
75897589
for (htlc_source, (htlc, _)) in monitor.get_pending_or_resolved_outbound_htlcs() {
75907590
if let HTLCSource::OutboundRoute { payment_id, session_priv, path, .. } = htlc_source {
7591-
if path.hops.is_empty() {
7591+
if path.len() == 0 {
75927592
log_error!(args.logger, "Got an empty path for a pending payment");
75937593
return Err(DecodeError::InvalidValue);
75947594
}
75957595

7596-
let path_amt = path.hops.last().unwrap().fee_msat;
7596+
let path_amt = path.final_value_msat();
75977597
let mut session_priv_bytes = [0; 32];
75987598
session_priv_bytes[..].copy_from_slice(&session_priv[..]);
75997599
match pending_outbounds.pending_outbound_payments.lock().unwrap().entry(payment_id) {
@@ -7603,7 +7603,7 @@ where
76037603
if newly_added { "Added" } else { "Had" }, path_amt, log_bytes!(session_priv_bytes), log_bytes!(htlc.payment_hash.0));
76047604
},
76057605
hash_map::Entry::Vacant(entry) => {
7606-
let path_fee = path.hops.get_path_fees();
7606+
let path_fee = path.fee_msat();
76077607
entry.insert(PendingOutboundPayment::Retryable {
76087608
retry_strategy: None,
76097609
attempts: PaymentAttempts::new(),

lightning/src/ln/outbound_payment.rs

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::events;
1818
use crate::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
1919
use crate::ln::channelmanager::{ChannelDetails, HTLCSource, IDEMPOTENCY_TIMEOUT_TICKS, PaymentId};
2020
use crate::ln::onion_utils::HTLCFailReason;
21-
use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteParameters, RoutePath, Router};
21+
use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteParameters, Router};
2222
use crate::util::errors::APIError;
2323
use crate::util::logger::Logger;
2424
use crate::util::time::Time;
@@ -174,10 +174,9 @@ impl PendingOutboundPayment {
174174
if remove_res {
175175
if let PendingOutboundPayment::Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, .. } = self {
176176
let path = path.expect("Fulfilling a payment should always come with a path");
177-
let path_last_hop = path.hops.last().expect("Outbound payments must have had a valid path");
178-
*pending_amt_msat -= path_last_hop.fee_msat;
177+
*pending_amt_msat -= path.final_value_msat();
179178
if let Some(fee_msat) = pending_fee_msat.as_mut() {
180-
*fee_msat -= path.hops.get_path_fees();
179+
*fee_msat -= path.fee_msat();
181180
}
182181
}
183182
}
@@ -195,10 +194,9 @@ impl PendingOutboundPayment {
195194
};
196195
if insert_res {
197196
if let PendingOutboundPayment::Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, .. } = self {
198-
let path_last_hop = path.hops.last().expect("Outbound payments must have had a valid path");
199-
*pending_amt_msat += path_last_hop.fee_msat;
197+
*pending_amt_msat += path.final_value_msat();
200198
if let Some(fee_msat) = pending_fee_msat.as_mut() {
201-
*fee_msat += path.hops.get_path_fees();
199+
*fee_msat += path.fee_msat();
202200
}
203201
}
204202
}
@@ -688,7 +686,7 @@ impl OutboundPayments {
688686
}
689687
};
690688
for path in route.paths.iter() {
691-
if path.hops.len() == 0 {
689+
if path.len() == 0 {
692690
log_error!(logger, "length-0 path in route");
693691
self.abandon_payment(payment_id, pending_events);
694692
return
@@ -720,7 +718,7 @@ impl OutboundPayments {
720718
PendingOutboundPayment::Retryable {
721719
total_msat, keysend_preimage, payment_secret, pending_amt_msat, ..
722720
} => {
723-
let retry_amt_msat: u64 = route.paths.iter().map(|path| path.hops.last().unwrap().fee_msat).sum();
721+
let retry_amt_msat = route.get_total_amount();
724722
if retry_amt_msat + *pending_amt_msat > *total_msat * (100 + RETRY_OVERFLOW_PERCENTAGE) / 100 {
725723
log_error!(logger, "retry_amt_msat of {} will put pending_amt_msat (currently: {}) more than 10% over total_payment_amt_msat of {}", retry_amt_msat, pending_amt_msat, total_msat);
726724
abandon_with_entry!(payment);
@@ -824,7 +822,7 @@ impl OutboundPayments {
824822
if let APIError::MonitorUpdateInProgress = e { continue }
825823
let mut failed_scid = None;
826824
if let APIError::ChannelUnavailable { .. } = e {
827-
let scid = path.hops[0].short_channel_id;
825+
let scid = path.first_hop_scid();
828826
failed_scid = Some(scid);
829827
route_params.payment_params.previously_failed_channels.push(scid);
830828
}
@@ -858,7 +856,7 @@ impl OutboundPayments {
858856

859857
let payment_hash = probing_cookie_from_id(&payment_id, probing_cookie_secret);
860858

861-
if path.hops.len() < 2 {
859+
if path.len() < 2 {
862860
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
863861
err: "No need probing a path with less than two hops".to_string()
864862
}))
@@ -946,17 +944,20 @@ impl OutboundPayments {
946944
let our_node_id = node_signer.get_node_id(Recipient::Node).unwrap(); // TODO no unwrap
947945
let mut path_errs = Vec::with_capacity(route.paths.len());
948946
'path_check: for path in route.paths.iter() {
949-
if path.hops.len() < 1 || path.hops.len() > 20 {
947+
if path.len() < 1 || path.len() > 20 {
950948
path_errs.push(Err(APIError::InvalidRoute{err: "Path didn't go anywhere/had bogus size".to_owned()}));
951949
continue 'path_check;
952950
}
953-
for (idx, hop) in path.hops.iter().enumerate() {
954-
if idx != path.hops.len() - 1 && hop.pubkey == our_node_id {
955-
path_errs.push(Err(APIError::InvalidRoute{err: "Path went through us but wasn't a simple rebalance loop to us".to_owned()}));
956-
continue 'path_check;
957-
}
951+
let we_are_intermed_hop = path.blinded_tail.as_ref().map_or_else(
952+
|| path.hops.split_last().map_or(false, |(_, path_prefix)| path_prefix.iter().any(|hop| hop.pubkey == our_node_id)),
953+
|tail|
954+
(tail.path.introduction_node_id == our_node_id && tail.path.blinded_hops.len() > 1)
955+
|| path.hops.iter().any(|hop| hop.pubkey == our_node_id));
956+
if we_are_intermed_hop {
957+
path_errs.push(Err(APIError::InvalidRoute{err: "Path went through us but wasn't a simple rebalance loop to us".to_owned()}));
958+
continue 'path_check;
958959
}
959-
total_value += path.hops.last().unwrap().fee_msat;
960+
total_value += path.final_value_msat();
960961
path_errs.push(Ok(()));
961962
}
962963
if path_errs.iter().any(|e| e.is_err()) {
@@ -1004,7 +1005,7 @@ impl OutboundPayments {
10041005
has_err = true;
10051006
has_ok = true;
10061007
} else if res.is_err() {
1007-
pending_amt_unsent += path.hops.last().unwrap().fee_msat;
1008+
pending_amt_unsent += path.final_value_msat();
10081009
}
10091010
}
10101011
if has_err && has_ok {

lightning/src/routing/router.rs

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,16 @@ pub struct Path {
304304
}
305305

306306
impl Path {
307+
/// Returns the total amount of fees paid on this [`Path`].
308+
pub fn fee_msat(&self) -> u64 {
309+
match &self.blinded_tail {
310+
Some(tail) => self.hops.iter().map(|hop| hop.fee_msat).sum::<u64>() + tail.fee_msat,
311+
None =>
312+
self.hops.split_last().map_or(0,
313+
|(_, path_prefix)| path_prefix.iter().map(|hop| hop.fee_msat).sum())
314+
}
315+
}
316+
307317
/// Returns the total amount paid on this [`Path`], excluding the fees.
308318
pub fn final_value_msat(&self) -> u64 {
309319
match &self.blinded_tail {
@@ -317,6 +327,18 @@ impl Path {
317327
self.hops.len() + self.blinded_tail.as_ref().map_or(0, |tail| tail.path.blinded_hops.len())
318328
}
319329

330+
pub(crate) fn first_hop_node_id(&self) -> PublicKey {
331+
self.hops.first().map_or_else(
332+
|| self.blinded_tail.as_ref().expect("Path had 0 hops").path.introduction_node_id,
333+
|hop| hop.pubkey)
334+
}
335+
336+
pub(crate) fn first_hop_scid(&self) -> u64 {
337+
self.hops.first().map_or_else(
338+
|| self.blinded_tail.as_ref().expect("Path had 0 hops").intro_node_scid,
339+
|hop| hop.short_channel_id)
340+
}
341+
320342
pub(super) fn node_id_scid_iter(&self) -> impl Iterator<Item=(PublicKey, u64)> + '_ {
321343
self.hops.iter().map(|hop| (hop.pubkey, hop.short_channel_id))
322344
.chain(self.blinded_tail.as_ref().map(|tail| (tail.path.introduction_node_id, tail.intro_node_scid)))
@@ -339,34 +361,19 @@ pub struct Route {
339361
pub payment_params: Option<PaymentParameters>,
340362
}
341363

342-
pub(crate) trait RoutePath {
343-
/// Gets the fees for a given path, excluding any excess paid to the recipient.
344-
fn get_path_fees(&self) -> u64;
345-
}
346-
impl RoutePath for Vec<RouteHop> {
347-
fn get_path_fees(&self) -> u64 {
348-
// Do not count last hop of each path since that's the full value of the payment
349-
self.split_last().map(|(_, path_prefix)| path_prefix).unwrap_or(&[])
350-
.iter().map(|hop| &hop.fee_msat)
351-
.sum()
352-
}
353-
}
354-
355364
impl Route {
356365
/// Returns the total amount of fees paid on this [`Route`].
357366
///
358367
/// This doesn't include any extra payment made to the recipient, which can happen in excess of
359368
/// the amount passed to [`find_route`]'s `params.final_value_msat`.
360369
pub fn get_total_fees(&self) -> u64 {
361-
self.paths.iter().map(|path| path.hops.get_path_fees()).sum()
370+
self.paths.iter().map(|path| path.fee_msat()).sum()
362371
}
363372

364373
/// Returns the total amount paid on this [`Route`], excluding the fees. Might be more than
365374
/// requested if we had to reach htlc_minimum_msat.
366375
pub fn get_total_amount(&self) -> u64 {
367-
return self.paths.iter()
368-
.map(|path| path.hops.split_last().map(|(hop, _)| hop.fee_msat).unwrap_or(0))
369-
.sum();
376+
self.paths.iter().map(|path| path.final_value_msat()).sum()
370377
}
371378
}
372379

0 commit comments

Comments
 (0)