Skip to content

Commit 0076635

Browse files
committed
Add a InflightHtlcs struct for tracking inflight HTLC information
Allows users to query for liquidity information without needing to know about the ordering we use to determine the direction a HTLC travels within a channel.
1 parent ea84acf commit 0076635

File tree

2 files changed

+34
-12
lines changed

2 files changed

+34
-12
lines changed

lightning-invoice/src/payment.rs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
//! # use lightning::util::logger::{Logger, Record};
4949
//! # use lightning::util::ser::{Writeable, Writer};
5050
//! # use lightning_invoice::Invoice;
51-
//! # use lightning_invoice::payment::{InvoicePayer, Payer, Retry, Router};
51+
//! # use lightning_invoice::payment::{InvoicePayer, Payer, Retry, Router, InflightHtlcs};
5252
//! # use secp256k1::PublicKey;
5353
//! # use std::cell::RefCell;
5454
//! # use std::ops::Deref;
@@ -83,7 +83,7 @@
8383
//! # impl Router for FakeRouter {
8484
//! # fn find_route(
8585
//! # &self, payer: &PublicKey, params: &RouteParameters, payment_hash: &PaymentHash,
86-
//! # first_hops: Option<&[&ChannelDetails]>, inflight_htlc_map: HashMap<(u64, bool), u64>
86+
//! # first_hops: Option<&[&ChannelDetails]>, _inflight_htlcs: InflightHtlcs
8787
//! # ) -> Result<Route, LightningError> { unimplemented!() }
8888
//! #
8989
//! # fn notify_payment_path_failed(&self, path: Vec<&RouteHop>, short_channel_id: u64) { unimplemented!() }
@@ -278,7 +278,7 @@ pub trait Router {
278278
/// Finds a [`Route`] between `payer` and `payee` for a payment with the given values.
279279
fn find_route(
280280
&self, payer: &PublicKey, route_params: &RouteParameters, payment_hash: &PaymentHash,
281-
first_hops: Option<&[&ChannelDetails]>, inflight_htlc_map: HashMap<(u64, bool), u64>
281+
first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InflightHtlcs
282282
) -> Result<Route, LightningError>;
283283
/// Lets the router know that payment through a specific path has failed.
284284
fn notify_payment_path_failed(&self, path: Vec<&RouteHop>, short_channel_id: u64);
@@ -455,7 +455,7 @@ where
455455
let inflight_htlcs = self.create_inflight_map();
456456
let route = self.router.find_route(
457457
&payer, &params, &payment_hash, Some(&first_hops.iter().collect::<Vec<_>>()),
458-
inflight_htlcs
458+
InflightHtlcs::new(Some(inflight_htlcs))
459459
).map_err(|e| PaymentError::Routing(e))?;
460460

461461
match send_payment(&route) {
@@ -560,7 +560,7 @@ where
560560

561561
let route = self.router.find_route(
562562
&payer, &params, &payment_hash, Some(&first_hops.iter().collect::<Vec<_>>()),
563-
inflight_htlcs
563+
InflightHtlcs::new(Some(inflight_htlcs))
564564
);
565565

566566
if route.is_err() {
@@ -740,6 +740,28 @@ where
740740
}
741741
}
742742

743+
/// Data structure used to track information about inflight HTLCs.
744+
pub struct InflightHtlcs {
745+
/// A map with liquidity value (in msat) keyed by a short channel id and the direction the HTLC
746+
/// is traveling in. The direction boolean is determined by checking if the HTLC source's public
747+
/// key is less than its destination. See [`InflightHtlcs::used_liquidity_msat`] for more
748+
/// details.
749+
pub map: HashMap<(u64, bool), u64>
750+
}
751+
752+
impl InflightHtlcs {
753+
/// Creates a new instance with an optional map of liquidity information.
754+
pub fn new(map: Option<HashMap<(u64, bool), u64>>) -> Self {
755+
InflightHtlcs { map: map.unwrap_or(HashMap::new()) }
756+
}
757+
758+
/// Returns liquidity in msat given the public key of the HTLC source, destination, and short
759+
/// channel id.
760+
pub fn used_liquidity_msat(&self, source: PublicKey, destination: PublicKey, channel_scid: u64) -> Option<&u64> {
761+
self.map.get(&(channel_scid, source < destination))
762+
}
763+
}
764+
743765
#[cfg(test)]
744766
mod tests {
745767
use super::*;
@@ -1817,7 +1839,7 @@ mod tests {
18171839
impl Router for TestRouter {
18181840
fn find_route(
18191841
&self, payer: &PublicKey, route_params: &RouteParameters, _payment_hash: &PaymentHash,
1820-
_first_hops: Option<&[&ChannelDetails]>, inflight_htlc_map: HashMap<(u64, bool), u64>
1842+
_first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InflightHtlcs
18211843
) -> Result<Route, LightningError> {
18221844
// Simulate calling the Scorer just as you would in find_route
18231845
let route = Self::route_for_value(route_params.final_value_msat);
@@ -1834,7 +1856,7 @@ mod tests {
18341856
// Since the path is reversed, the last element in our iteration is the first
18351857
// hop.
18361858
let mut locked_scorer = self.scorer.lock();
1837-
let scorer = AccountForInFlightHtlcs::new(locked_scorer.deref_mut(), inflight_htlc_map.clone());
1859+
let scorer = AccountForInFlightHtlcs::new(locked_scorer.deref_mut(), inflight_htlcs.map.clone());
18381860
if idx == path.len() - 1 {
18391861
scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(payer), &NodeId::from_pubkey(&hop.pubkey), usage);
18401862
} else {
@@ -1870,7 +1892,7 @@ mod tests {
18701892
impl Router for FailingRouter {
18711893
fn find_route(
18721894
&self, _payer: &PublicKey, _params: &RouteParameters, _payment_hash: &PaymentHash,
1873-
_first_hops: Option<&[&ChannelDetails]>, _inflight_htlc_map: HashMap<(u64, bool), u64>
1895+
_first_hops: Option<&[&ChannelDetails]>, _inflight_htlcs: InflightHtlcs
18741896
) -> Result<Route, LightningError> {
18751897
Err(LightningError { err: String::new(), action: ErrorAction::IgnoreError })
18761898
}
@@ -2132,7 +2154,7 @@ mod tests {
21322154
impl Router for ManualRouter {
21332155
fn find_route(
21342156
&self, _payer: &PublicKey, _params: &RouteParameters, _payment_hash: &PaymentHash,
2135-
_first_hops: Option<&[&ChannelDetails]>, _inflight_htlc_map: HashMap<(u64, bool), u64>
2157+
_first_hops: Option<&[&ChannelDetails]>, _inflight_htlcs: InflightHtlcs
21362158
) -> Result<Route, LightningError> {
21372159
self.0.borrow_mut().pop_front().unwrap()
21382160
}

lightning-invoice/src/utils.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Convenient utilities to create an invoice.
22
33
use {CreationError, Currency, Invoice, InvoiceBuilder, SignOrCreationError};
4-
use payment::{Payer, Router};
4+
use payment::{InflightHtlcs, Payer, Router};
55

66
use crate::{prelude::*, Description, InvoiceDescription, Sha256};
77
use bech32::ToBase32;
@@ -468,7 +468,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> Router for DefaultR
468468
{
469469
fn find_route(
470470
&self, payer: &PublicKey, params: &RouteParameters, _payment_hash: &PaymentHash,
471-
first_hops: Option<&[&ChannelDetails]>, inflight_htlc_map: HashMap<(u64, bool), u64>
471+
first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InflightHtlcs
472472
) -> Result<Route, LightningError> {
473473
let random_seed_bytes = {
474474
let mut locked_random_seed_bytes = self.random_seed_bytes.lock().unwrap();
@@ -478,7 +478,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> Router for DefaultR
478478

479479
find_route(
480480
payer, params, &self.network_graph, first_hops, &*self.logger,
481-
&AccountForInFlightHtlcs::new(&mut self.scorer.lock(), inflight_htlc_map),
481+
&AccountForInFlightHtlcs::new(&mut self.scorer.lock(), inflight_htlcs.map),
482482
&random_seed_bytes
483483
)
484484
}

0 commit comments

Comments
 (0)