Skip to content

Commit 8ca1acc

Browse files
committed
Move Scorer requirement away from Router trait
We do this to enable users to create routers that do not need a scorer. This can be useful if they are running a node the delegates pathfinding. We replace the `scorer` parameter in `find_route` with `inflight_map`, so `InvoicePayer` can still hand off a map of inflight HTLCs. It can also be left empty. Then, we move `AccountsForInflightHtlcs` to `DefaultRouter`, which we will use to wrap the new `scorer` field, so scoring only happens in `DefaultRouter` explicitly.
1 parent f99301d commit 8ca1acc

File tree

2 files changed

+76
-60
lines changed

2 files changed

+76
-60
lines changed

lightning-invoice/src/payment.rs

Lines changed: 5 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
145145
use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
146146
use lightning::ln::msgs::LightningError;
147147
use lightning::routing::gossip::NodeId;
148-
use lightning::routing::scoring::{ChannelUsage, LockableScore, Score};
148+
use lightning::routing::scoring::LockableScore;
149149
use lightning::routing::router::{PaymentParameters, Route, RouteHop, RouteParameters};
150150
use lightning::util::errors::APIError;
151151
use lightning::util::events::{Event, EventHandler};
@@ -209,49 +209,6 @@ impl<T: Time> PaymentInfo<T> {
209209
}
210210
}
211211

212-
/// Used to store information about all the HTLCs that are inflight across all payment attempts
213-
struct AccountForInFlightHtlcs<'a, S: Score> {
214-
scorer: &'a mut S,
215-
/// Maps a channel's short channel id and its direction to the liquidity used up.
216-
inflight_htlcs: HashMap<(u64, bool), u64>,
217-
}
218-
219-
#[cfg(c_bindings)]
220-
impl<'a, S:Score> lightning::util::ser::Writeable for AccountForInFlightHtlcs<'a, S> {
221-
fn write<W: lightning::util::ser::Writer>(&self, writer: &mut W) -> Result<(), std::io::Error> { self.scorer.write(writer) }
222-
}
223-
224-
impl<'a, S: Score> Score for AccountForInFlightHtlcs<'a, S> {
225-
fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage) -> u64 {
226-
if let Some(used_liqudity) = self.inflight_htlcs.get(&(short_channel_id, source < target)) {
227-
let usage = ChannelUsage {
228-
inflight_htlc_msat: usage.inflight_htlc_msat + used_liqudity,
229-
..usage
230-
};
231-
232-
self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
233-
} else {
234-
self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
235-
}
236-
}
237-
238-
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
239-
self.scorer.payment_path_failed(path, short_channel_id)
240-
}
241-
242-
fn payment_path_successful(&mut self, path: &[&RouteHop]) {
243-
self.scorer.payment_path_successful(path)
244-
}
245-
246-
fn probe_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
247-
self.scorer.probe_failed(path, short_channel_id)
248-
}
249-
250-
fn probe_successful(&mut self, path: &[&RouteHop]) {
251-
self.scorer.probe_successful(path)
252-
}
253-
}
254-
255212
/// Storing minimal payment attempts information required for determining if a outbound payment can
256213
/// be retried.
257214
#[derive(Clone, Copy)]
@@ -314,9 +271,9 @@ pub trait Payer {
314271
/// A trait defining behavior for routing an [`Invoice`] payment.
315272
pub trait Router {
316273
/// Finds a [`Route`] between `payer` and `payee` for a payment with the given values.
317-
fn find_route<S: Score>(
274+
fn find_route(
318275
&self, payer: &PublicKey, route_params: &RouteParameters, payment_hash: &PaymentHash,
319-
first_hops: Option<&[&ChannelDetails]>, scorer: &S
276+
first_hops: Option<&[&ChannelDetails]>, inflight_htlc_map: HashMap<(u64, bool), u64>
320277
) -> Result<Route, LightningError>;
321278
}
322279

@@ -487,7 +444,7 @@ where
487444
let inflight_htlcs = self.create_inflight_map();
488445
let route = self.router.find_route(
489446
&payer, &params, &payment_hash, Some(&first_hops.iter().collect::<Vec<_>>()),
490-
&AccountForInFlightHtlcs { scorer: &mut self.scorer.lock(), inflight_htlcs }
447+
inflight_htlcs
491448
).map_err(|e| PaymentError::Routing(e))?;
492449

493450
match send_payment(&route) {
@@ -592,7 +549,7 @@ where
592549

593550
let route = self.router.find_route(
594551
&payer, &params, &payment_hash, Some(&first_hops.iter().collect::<Vec<_>>()),
595-
&AccountForInFlightHtlcs { scorer: &mut self.scorer.lock(), inflight_htlcs }
552+
inflight_htlcs
596553
);
597554

598555
if route.is_err() {

lightning-invoice/src/utils.rs

Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ use lightning::ln::channelmanager::{ChannelDetails, ChannelManager, PaymentId, P
1515
use lightning::ln::channelmanager::{PhantomRouteHints, MIN_CLTV_EXPIRY_DELTA};
1616
use lightning::ln::inbound_payment::{create, create_from_hash, ExpandedKey};
1717
use lightning::ln::msgs::LightningError;
18-
use lightning::routing::gossip::{NetworkGraph, RoutingFees};
19-
use lightning::routing::router::{Route, RouteHint, RouteHintHop, RouteParameters, find_route};
20-
use lightning::routing::scoring::Score;
18+
use lightning::routing::gossip::{NetworkGraph, NodeId, RoutingFees};
19+
use lightning::routing::router::{Route, RouteHint, RouteHintHop, RouteParameters, find_route, RouteHop};
20+
use lightning::routing::scoring::{ChannelUsage, LockableScore, Score};
2121
use lightning::util::logger::Logger;
2222
use secp256k1::PublicKey;
2323
use core::ops::Deref;
@@ -440,33 +440,47 @@ fn filter_channels(channels: Vec<ChannelDetails>, min_inbound_capacity_msat: Opt
440440
}
441441

442442
/// A [`Router`] implemented using [`find_route`].
443-
pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>>, L: Deref> where L::Target: Logger {
443+
pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> where
444+
L::Target: Logger,
445+
S::Target: for <'a> LockableScore<'a>,
446+
{
444447
network_graph: G,
445448
logger: L,
446449
random_seed_bytes: Mutex<[u8; 32]>,
450+
scorer: S
447451
}
448452

449-
impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> DefaultRouter<G, L> where L::Target: Logger {
453+
impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> DefaultRouter<G, L, S> where
454+
L::Target: Logger,
455+
S::Target: for <'a> LockableScore<'a>,
456+
{
450457
/// Creates a new router using the given [`NetworkGraph`], a [`Logger`], and a randomness source
451458
/// `random_seed_bytes`.
452-
pub fn new(network_graph: G, logger: L, random_seed_bytes: [u8; 32]) -> Self {
459+
pub fn new(network_graph: G, logger: L, random_seed_bytes: [u8; 32], scorer: S) -> Self {
453460
let random_seed_bytes = Mutex::new(random_seed_bytes);
454-
Self { network_graph, logger, random_seed_bytes }
461+
Self { network_graph, logger, random_seed_bytes, scorer }
455462
}
456463
}
457464

458-
impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> Router for DefaultRouter<G, L>
459-
where L::Target: Logger {
460-
fn find_route<S: Score>(
465+
impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> Router for DefaultRouter<G, L, S> where
466+
L::Target: Logger,
467+
S::Target: for <'a> LockableScore<'a>,
468+
{
469+
fn find_route(
461470
&self, payer: &PublicKey, params: &RouteParameters, _payment_hash: &PaymentHash,
462-
first_hops: Option<&[&ChannelDetails]>, scorer: &S
471+
first_hops: Option<&[&ChannelDetails]>, inflight_htlc_map: HashMap<(u64, bool), u64>
463472
) -> Result<Route, LightningError> {
464473
let random_seed_bytes = {
465474
let mut locked_random_seed_bytes = self.random_seed_bytes.lock().unwrap();
466475
*locked_random_seed_bytes = sha256::Hash::hash(&*locked_random_seed_bytes).into_inner();
467476
*locked_random_seed_bytes
468477
};
469-
find_route(payer, params, &self.network_graph, first_hops, &*self.logger, scorer, &random_seed_bytes)
478+
479+
find_route(
480+
payer, params, &self.network_graph, first_hops, &*self.logger,
481+
&AccountForInFlightHtlcs { scorer: &mut self.scorer.lock(), inflight_htlcs: inflight_htlc_map },
482+
&random_seed_bytes
483+
)
470484
}
471485
}
472486

@@ -510,6 +524,51 @@ where
510524
}
511525
}
512526

527+
528+
/// Used to store information about all the HTLCs that are inflight across all payment attempts
529+
struct AccountForInFlightHtlcs<'a, S: Score> {
530+
scorer: &'a mut S,
531+
/// Maps a channel's short channel id and its direction to the liquidity used up.
532+
inflight_htlcs: HashMap<(u64, bool), u64>,
533+
}
534+
535+
#[cfg(c_bindings)]
536+
impl<'a, S:Score> lightning::util::ser::Writeable for AccountForInFlightHtlcs<'a, S> {
537+
fn write<W: lightning::util::ser::Writer>(&self, writer: &mut W) -> Result<(), std::io::Error> { self.scorer.write(writer) }
538+
}
539+
540+
impl<'a, S: Score> Score for AccountForInFlightHtlcs<'a, S> {
541+
fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage) -> u64 {
542+
if let Some(used_liqudity) = self.inflight_htlcs.get(&(short_channel_id, source < target)) {
543+
let usage = ChannelUsage {
544+
inflight_htlc_msat: usage.inflight_htlc_msat + used_liqudity,
545+
..usage
546+
};
547+
548+
self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
549+
} else {
550+
self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
551+
}
552+
}
553+
554+
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
555+
self.scorer.payment_path_failed(path, short_channel_id)
556+
}
557+
558+
fn payment_path_successful(&mut self, path: &[&RouteHop]) {
559+
self.scorer.payment_path_successful(path)
560+
}
561+
562+
fn probe_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
563+
self.scorer.probe_failed(path, short_channel_id)
564+
}
565+
566+
fn probe_successful(&mut self, path: &[&RouteHop]) {
567+
self.scorer.probe_successful(path)
568+
}
569+
}
570+
571+
513572
#[cfg(test)]
514573
mod test {
515574
use core::time::Duration;

0 commit comments

Comments
 (0)