Skip to content

Commit 7a91ea9

Browse files
Account for Path::blinded_tail in scoring
1 parent 4299b14 commit 7a91ea9

File tree

2 files changed

+79
-21
lines changed

2 files changed

+79
-21
lines changed

lightning/src/routing/router.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,14 @@ pub struct Path {
295295
}
296296

297297
impl Path {
298+
/// Returns the total amount paid on this [`Path`], excluding the fees.
299+
pub fn final_value_msat(&self) -> u64 {
300+
match &self.blinded_tail {
301+
Some(blinded_tail) => blinded_tail.final_value_msat,
302+
None => self.hops.last().map_or(0, |hop| hop.fee_msat)
303+
}
304+
}
305+
298306
/// The length of this path, including the hops of its [`Path::blinded_tail`], if any.
299307
pub fn len(&self) -> usize {
300308
self.hops.len() + self.blinded_tail.as_ref().map_or(0, |tail| tail.hops.len().saturating_sub(1)) // Don't double count the intro node

lightning/src/routing/scoring.rs

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,66 +1234,74 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
12341234
}
12351235

12361236
fn payment_path_failed(&mut self, path: &Path, short_channel_id: u64) {
1237-
let amount_msat = path.hops.split_last().map(|(hop, _)| hop.fee_msat).unwrap_or(0);
1237+
let amount_msat = path.final_value_msat();
12381238
log_trace!(self.logger, "Scoring path through to SCID {} as having failed at {} msat", short_channel_id, amount_msat);
12391239
let network_graph = self.network_graph.read_only();
1240-
for (hop_idx, hop) in path.hops.iter().enumerate() {
1241-
let target = NodeId::from_pubkey(&hop.pubkey);
1240+
for (hop_idx, (pubkey, scid)) in path.hops.iter().map(|hop| (hop.pubkey, hop.short_channel_id))
1241+
.chain(path.blinded_tail.as_ref().map(|tail| (tail.path.introduction_node_id, tail.intro_node_scid)))
1242+
.enumerate()
1243+
{
1244+
let target = NodeId::from_pubkey(&pubkey);
12421245
let channel_directed_from_source = network_graph.channels()
1243-
.get(&hop.short_channel_id)
1246+
.get(&scid)
12441247
.and_then(|channel| channel.as_directed_to(&target));
12451248

1246-
let at_failed_channel = hop.short_channel_id == short_channel_id;
1249+
let at_failed_channel = scid == short_channel_id;
12471250
if at_failed_channel && hop_idx == 0 {
1248-
log_warn!(self.logger, "Payment failed at the first hop - we do not attempt to learn channel info in such cases as we can directly observe local state.\n\tBecause we know the local state, we should generally not see failures here - this may be an indication that your channel peer on channel {} is broken and you may wish to close the channel.", hop.short_channel_id);
1251+
log_warn!(self.logger, "Payment failed at the first hop - we do not attempt to learn channel info in such cases as we can directly observe local state.\n\tBecause we know the local state, we should generally not see failures here - this may be an indication that your channel peer on channel {} is broken and you may wish to close the channel.", scid);
12491252
}
12501253

12511254
// Only score announced channels.
12521255
if let Some((channel, source)) = channel_directed_from_source {
12531256
let capacity_msat = channel.effective_capacity().as_msat();
12541257
if at_failed_channel {
12551258
self.channel_liquidities
1256-
.entry(hop.short_channel_id)
1259+
.entry(scid)
12571260
.or_insert_with(ChannelLiquidity::new)
12581261
.as_directed_mut(source, &target, 0, capacity_msat, &self.params)
1259-
.failed_at_channel(amount_msat, format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
1262+
.failed_at_channel(amount_msat, format_args!("SCID {}, towards {:?}", scid, target), &self.logger);
12601263
} else {
12611264
self.channel_liquidities
1262-
.entry(hop.short_channel_id)
1265+
.entry(scid)
12631266
.or_insert_with(ChannelLiquidity::new)
12641267
.as_directed_mut(source, &target, 0, capacity_msat, &self.params)
1265-
.failed_downstream(amount_msat, format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
1268+
.failed_downstream(amount_msat, format_args!("SCID {}, towards {:?}", scid, target), &self.logger);
12661269
}
12671270
} else {
12681271
log_debug!(self.logger, "Not able to penalize channel with SCID {} as we do not have graph info for it (likely a route-hint last-hop).",
1269-
hop.short_channel_id);
1272+
scid);
12701273
}
12711274
if at_failed_channel { break; }
12721275
}
12731276
}
12741277

12751278
fn payment_path_successful(&mut self, path: &Path) {
1276-
let amount_msat = path.hops.split_last().map(|(hop, _)| hop.fee_msat).unwrap_or(0);
1279+
let amount_msat = path.final_value_msat();
1280+
let final_scid = path.blinded_tail.as_ref().map_or_else(
1281+
|| path.hops.last().map_or(0, |hop| hop.short_channel_id),
1282+
|tail| tail.intro_node_scid);
12771283
log_trace!(self.logger, "Scoring path through SCID {} as having succeeded at {} msat.",
1278-
path.hops.split_last().map(|(hop, _)| hop.short_channel_id).unwrap_or(0), amount_msat);
1284+
final_scid, amount_msat);
12791285
let network_graph = self.network_graph.read_only();
1280-
for hop in &path.hops {
1281-
let target = NodeId::from_pubkey(&hop.pubkey);
1286+
for (pubkey, scid) in path.hops.iter().map(|hop| (hop.pubkey, hop.short_channel_id))
1287+
.chain(path.blinded_tail.as_ref().map(|tail| (tail.path.introduction_node_id, tail.intro_node_scid)))
1288+
{
1289+
let target = NodeId::from_pubkey(&pubkey);
12821290
let channel_directed_from_source = network_graph.channels()
1283-
.get(&hop.short_channel_id)
1291+
.get(&scid)
12841292
.and_then(|channel| channel.as_directed_to(&target));
12851293

12861294
// Only score announced channels.
12871295
if let Some((channel, source)) = channel_directed_from_source {
12881296
let capacity_msat = channel.effective_capacity().as_msat();
12891297
self.channel_liquidities
1290-
.entry(hop.short_channel_id)
1298+
.entry(scid)
12911299
.or_insert_with(ChannelLiquidity::new)
12921300
.as_directed_mut(source, &target, 0, capacity_msat, &self.params)
1293-
.successful(amount_msat, format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
1301+
.successful(amount_msat, format_args!("SCID {}, towards {:?}", scid, target), &self.logger);
12941302
} else {
12951303
log_debug!(self.logger, "Not able to learn for channel with SCID {} as we do not have graph info for it (likely a route-hint last-hop).",
1296-
hop.short_channel_id);
1304+
scid);
12971305
}
12981306
}
12991307
}
@@ -1702,17 +1710,18 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
17021710
#[cfg(test)]
17031711
mod tests {
17041712
use super::{ChannelLiquidity, HistoricalBucketRangeTracker, ProbabilisticScoringParameters, ProbabilisticScorerUsingTime};
1713+
use crate::blinded_path::BlindedPath;
17051714
use crate::util::config::UserConfig;
17061715
use crate::util::time::Time;
17071716
use crate::util::time::tests::SinceEpoch;
17081717

17091718
use crate::ln::channelmanager;
17101719
use crate::ln::msgs::{ChannelAnnouncement, ChannelUpdate, UnsignedChannelAnnouncement, UnsignedChannelUpdate};
17111720
use crate::routing::gossip::{EffectiveCapacity, NetworkGraph, NodeId};
1712-
use crate::routing::router::{Path, RouteHop};
1721+
use crate::routing::router::{BlindedTail, Path, RouteHop};
17131722
use crate::routing::scoring::{ChannelUsage, Score};
17141723
use crate::util::ser::{ReadableArgs, Writeable};
1715-
use crate::util::test_utils::TestLogger;
1724+
use crate::util::test_utils::{self, TestLogger};
17161725

17171726
use bitcoin::blockdata::constants::genesis_block;
17181727
use bitcoin::hashes::Hash;
@@ -2870,4 +2879,45 @@ mod tests {
28702879
};
28712880
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
28722881
}
2882+
2883+
#[test]
2884+
fn scores_intro_node_scid() {
2885+
// Make sure we'll score the scid contained in the blinded portion of a path
2886+
let logger = TestLogger::new();
2887+
let network_graph = network_graph(&logger);
2888+
let params = ProbabilisticScoringParameters {
2889+
liquidity_penalty_multiplier_msat: 1_000,
2890+
liquidity_offset_half_life: Duration::from_secs(10),
2891+
..ProbabilisticScoringParameters::zero_penalty()
2892+
};
2893+
let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
2894+
let source = source_node_id();
2895+
let target = target_node_id();
2896+
let usage = ChannelUsage {
2897+
amount_msat: 512,
2898+
inflight_htlc_msat: 0,
2899+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_000 },
2900+
};
2901+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
2902+
2903+
let mut path = payment_path_for_amount(768);
2904+
let last_hop = path.hops.pop().unwrap();
2905+
let _intro_node_hop = path.hops.pop().unwrap();
2906+
path.blinded_tail = Some(BlindedTail {
2907+
path: BlindedPath {
2908+
introduction_node_id: target_pubkey(),
2909+
blinding_point: test_utils::pubkey(42),
2910+
blinded_hops: Vec::new(),
2911+
},
2912+
fee_msat: 2,
2913+
cltv_expiry_delta: last_hop.cltv_expiry_delta,
2914+
final_value_msat: last_hop.fee_msat,
2915+
intro_node_scid: 42,
2916+
});
2917+
2918+
scorer.payment_path_failed(&path, 42);
2919+
path.blinded_tail.as_mut().unwrap().final_value_msat = 256;
2920+
scorer.payment_path_failed(&path, 43);
2921+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 281);
2922+
}
28732923
}

0 commit comments

Comments
 (0)