From 585f8d8150d9e353b74a8f13e3042c607fa65377 Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Tue, 28 Jun 2022 14:50:10 +0200 Subject: [PATCH] Provide add probing interface to `Scorer` --- lightning-invoice/src/payment.rs | 87 +++++++++++++++++++++++++++----- lightning/src/routing/router.rs | 8 +++ lightning/src/routing/scoring.rs | 26 ++++++++++ 3 files changed, 107 insertions(+), 14 deletions(-) diff --git a/lightning-invoice/src/payment.rs b/lightning-invoice/src/payment.rs index 992f7105bcd..2f22ed48f95 100644 --- a/lightning-invoice/src/payment.rs +++ b/lightning-invoice/src/payment.rs @@ -104,6 +104,8 @@ //! # ) -> u64 { 0 } //! # fn payment_path_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {} //! # fn payment_path_successful(&mut self, _path: &[&RouteHop]) {} +//! # fn probe_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {} +//! # fn probe_successful(&mut self, _path: &[&RouteHop]) {} //! # } //! # //! # struct FakeLogger {} @@ -595,8 +597,11 @@ where // hop and then drop the event instead of handing it up to the user's event // handler. if self.payer.payment_is_probe(*payment_hash, *payment_id) { - let scid = if *rejected_by_dest { u64::max_value() } else { *short_channel_id }; - self.scorer.lock().payment_path_failed(&path, scid); + if *rejected_by_dest { + self.scorer.lock().probe_successful(&path); + } else { + self.scorer.lock().probe_failed(&path, *short_channel_id); + } return; } } @@ -1345,7 +1350,7 @@ mod tests { .expect_send(Amount::ForInvoice(final_value_msat)) .expect_send(Amount::OnRetry(final_value_msat / 2)); let router = TestRouter {}; - let scorer = RefCell::new(TestScorer::new().expect(PaymentPath::Failure { + let scorer = RefCell::new(TestScorer::new().expect(ExpectedPaymentResult::PathFailure { path: path.clone(), short_channel_id: path[0].short_channel_id, })); let logger = TestLogger::new(); @@ -1381,8 +1386,8 @@ mod tests { let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat)); let router = TestRouter {}; let scorer = RefCell::new(TestScorer::new() - .expect(PaymentPath::Success { path: route.paths[0].clone() }) - .expect(PaymentPath::Success { path: route.paths[1].clone() }) + .expect(ExpectedPaymentResult::PathSuccess { path: route.paths[0].clone() }) + .expect(ExpectedPaymentResult::PathSuccess { path: route.paths[1].clone() }) ); let logger = TestLogger::new(); let invoice_payer = @@ -1479,13 +1484,15 @@ mod tests { } struct TestScorer { - expectations: Option>, + expectations: Option>, } #[derive(Debug)] - enum PaymentPath { - Failure { path: Vec, short_channel_id: u64 }, - Success { path: Vec }, + enum ExpectedPaymentResult { + PathFailure { path: Vec, short_channel_id: u64 }, + PathSuccess { path: Vec }, + ProbeFailure { path: Vec, short_channel_id: u64 }, + ProbeSuccess { path: Vec }, } impl TestScorer { @@ -1495,7 +1502,7 @@ mod tests { } } - fn expect(mut self, expectation: PaymentPath) -> Self { + fn expect(mut self, expectation: ExpectedPaymentResult) -> Self { self.expectations.get_or_insert_with(|| VecDeque::new()).push_back(expectation); self } @@ -1514,13 +1521,19 @@ mod tests { fn payment_path_failed(&mut self, actual_path: &[&RouteHop], actual_short_channel_id: u64) { if let Some(expectations) = &mut self.expectations { match expectations.pop_front() { - Some(PaymentPath::Failure { path, short_channel_id }) => { + Some(ExpectedPaymentResult::PathFailure { path, short_channel_id }) => { assert_eq!(actual_path, &path.iter().collect::>()[..]); assert_eq!(actual_short_channel_id, short_channel_id); }, - Some(PaymentPath::Success { path }) => { + Some(ExpectedPaymentResult::PathSuccess { path }) => { panic!("Unexpected successful payment path: {:?}", path) }, + Some(ExpectedPaymentResult::ProbeFailure { path, .. }) => { + panic!("Unexpected failed payment probe: {:?}", path) + }, + Some(ExpectedPaymentResult::ProbeSuccess { path }) => { + panic!("Unexpected successful payment probe: {:?}", path) + }, None => panic!("Unexpected payment_path_failed call: {:?}", actual_path), } } @@ -1529,10 +1542,56 @@ mod tests { fn payment_path_successful(&mut self, actual_path: &[&RouteHop]) { if let Some(expectations) = &mut self.expectations { match expectations.pop_front() { - Some(PaymentPath::Failure { path, .. }) => { + Some(ExpectedPaymentResult::PathFailure { path, .. }) => { panic!("Unexpected payment path failure: {:?}", path) }, - Some(PaymentPath::Success { path }) => { + Some(ExpectedPaymentResult::PathSuccess { path }) => { + assert_eq!(actual_path, &path.iter().collect::>()[..]); + }, + Some(ExpectedPaymentResult::ProbeFailure { path, .. }) => { + panic!("Unexpected failed payment probe: {:?}", path) + }, + Some(ExpectedPaymentResult::ProbeSuccess { path }) => { + panic!("Unexpected successful payment probe: {:?}", path) + }, + None => panic!("Unexpected payment_path_successful call: {:?}", actual_path), + } + } + } + + fn probe_failed(&mut self, actual_path: &[&RouteHop], actual_short_channel_id: u64) { + if let Some(expectations) = &mut self.expectations { + match expectations.pop_front() { + Some(ExpectedPaymentResult::PathFailure { path, .. }) => { + panic!("Unexpected failed payment path: {:?}", path) + }, + Some(ExpectedPaymentResult::PathSuccess { path }) => { + panic!("Unexpected successful payment path: {:?}", path) + }, + Some(ExpectedPaymentResult::ProbeFailure { path, short_channel_id }) => { + assert_eq!(actual_path, &path.iter().collect::>()[..]); + assert_eq!(actual_short_channel_id, short_channel_id); + }, + Some(ExpectedPaymentResult::ProbeSuccess { path }) => { + panic!("Unexpected successful payment probe: {:?}", path) + }, + None => panic!("Unexpected payment_path_failed call: {:?}", actual_path), + } + } + } + fn probe_successful(&mut self, actual_path: &[&RouteHop]) { + if let Some(expectations) = &mut self.expectations { + match expectations.pop_front() { + Some(ExpectedPaymentResult::PathFailure { path, .. }) => { + panic!("Unexpected payment path failure: {:?}", path) + }, + Some(ExpectedPaymentResult::PathSuccess { path }) => { + panic!("Unexpected successful payment path: {:?}", path) + }, + Some(ExpectedPaymentResult::ProbeFailure { path, .. }) => { + panic!("Unexpected failed payment probe: {:?}", path) + }, + Some(ExpectedPaymentResult::ProbeSuccess { path }) => { assert_eq!(actual_path, &path.iter().collect::>()[..]); }, None => panic!("Unexpected payment_path_successful call: {:?}", actual_path), diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 3b417d347c8..81d72907d62 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -1849,6 +1849,10 @@ fn build_route_from_hops_internal( fn payment_path_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {} fn payment_path_successful(&mut self, _path: &[&RouteHop]) {} + + fn probe_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {} + + fn probe_successful(&mut self, _path: &[&RouteHop]) {} } impl<'a> Writeable for HopScorer { @@ -5314,6 +5318,8 @@ mod tests { fn payment_path_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {} fn payment_path_successful(&mut self, _path: &[&RouteHop]) {} + fn probe_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {} + fn probe_successful(&mut self, _path: &[&RouteHop]) {} } struct BadNodeScorer { @@ -5332,6 +5338,8 @@ mod tests { fn payment_path_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {} fn payment_path_successful(&mut self, _path: &[&RouteHop]) {} + fn probe_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {} + fn probe_successful(&mut self, _path: &[&RouteHop]) {} } #[test] diff --git a/lightning/src/routing/scoring.rs b/lightning/src/routing/scoring.rs index 77b76a0825b..ca52ac7a376 100644 --- a/lightning/src/routing/scoring.rs +++ b/lightning/src/routing/scoring.rs @@ -102,6 +102,12 @@ pub trait Score $(: $supertrait)* { /// Handles updating channel penalties after successfully routing along a path. fn payment_path_successful(&mut self, path: &[&RouteHop]); + + /// Handles updating channel penalties after a probe over the given path failed. + fn probe_failed(&mut self, path: &[&RouteHop], short_channel_id: u64); + + /// Handles updating channel penalties after a probe over the given path succeeded. + fn probe_successful(&mut self, path: &[&RouteHop]); } impl $(+ $supertrait)*> Score for T { @@ -118,6 +124,14 @@ impl $(+ $supertrait)*> Score for T { fn payment_path_successful(&mut self, path: &[&RouteHop]) { self.deref_mut().payment_path_successful(path) } + + fn probe_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) { + self.deref_mut().probe_failed(path, short_channel_id) + } + + fn probe_successful(&mut self, path: &[&RouteHop]) { + self.deref_mut().probe_successful(path) + } } } } @@ -241,6 +255,10 @@ impl Score for FixedPenaltyScorer { fn payment_path_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {} fn payment_path_successful(&mut self, _path: &[&RouteHop]) {} + + fn probe_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {} + + fn probe_successful(&mut self, _path: &[&RouteHop]) {} } impl Writeable for FixedPenaltyScorer { @@ -811,6 +829,14 @@ impl>, L: Deref, T: Time> Score for Probabilis } } } + + fn probe_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) { + self.payment_path_failed(path, short_channel_id) + } + + fn probe_successful(&mut self, path: &[&RouteHop]) { + self.payment_path_failed(path, u64::max_value()) + } } mod approx {