32
32
//! # use lightning::ln::msgs::LightningError;
33
33
//! # use lightning::routing;
34
34
//! # use lightning::routing::network_graph::NodeId;
35
- //! # use lightning::routing::router::{Route, RouteParameters};
35
+ //! # use lightning::routing::router::{Route, RouteHop, RouteParameters};
36
36
//! # use lightning::util::events::{Event, EventHandler, EventsProvider};
37
37
//! # use lightning::util::logger::{Logger, Record};
38
38
//! # use lightning_invoice::Invoice;
70
70
//! # fn channel_penalty_msat(
71
71
//! # &self, _short_channel_id: u64, _source: &NodeId, _target: &NodeId
72
72
//! # ) -> u64 { 0 }
73
+ //! # fn payment_path_failed(&mut self, _path: &Vec<RouteHop>, _short_channel_id: u64) {}
73
74
//! # }
74
75
//! #
75
76
//! # struct FakeLogger {};
@@ -124,7 +125,7 @@ use secp256k1::key::PublicKey;
124
125
125
126
use std:: collections:: hash_map:: { self , HashMap } ;
126
127
use std:: ops:: Deref ;
127
- use std:: sync:: Mutex ;
128
+ use std:: sync:: { Mutex , RwLock } ;
128
129
use std:: time:: { Duration , SystemTime } ;
129
130
130
131
/// A utility for paying [`Invoice]`s.
@@ -138,7 +139,7 @@ where
138
139
{
139
140
payer : P ,
140
141
router : R ,
141
- scorer : S ,
142
+ scorer : RwLock < S > ,
142
143
logger : L ,
143
144
event_handler : E ,
144
145
payment_cache : Mutex < HashMap < PaymentHash , usize > > ,
@@ -204,14 +205,22 @@ where
204
205
Self {
205
206
payer,
206
207
router,
207
- scorer,
208
+ scorer : RwLock :: new ( scorer ) ,
208
209
logger,
209
210
event_handler,
210
211
payment_cache : Mutex :: new ( HashMap :: new ( ) ) ,
211
212
retry_attempts,
212
213
}
213
214
}
214
215
216
+ /// Returns a read-only reference to the parameterized [`routing::Score`].
217
+ ///
218
+ /// Useful if the scorer needs to be persisted. Be sure to drop the returned guard immediately
219
+ /// after use since retrying failed payment paths require write access.
220
+ pub fn scorer ( & self ) -> std:: sync:: RwLockReadGuard < ' _ , S > {
221
+ self . scorer . read ( ) . unwrap ( )
222
+ }
223
+
215
224
/// Pays the given [`Invoice`], caching it for later use in case a retry is needed.
216
225
pub fn pay_invoice ( & self , invoice : & Invoice ) -> Result < PaymentId , PaymentError > {
217
226
if invoice. amount_milli_satoshis ( ) . is_none ( ) {
@@ -258,7 +267,7 @@ where
258
267
& payer,
259
268
& params,
260
269
Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) ,
261
- & self . scorer ,
270
+ & * self . scorer . read ( ) . unwrap ( ) ,
262
271
) . map_err ( |e| PaymentError :: Routing ( e) ) ?;
263
272
264
273
let payment_hash = PaymentHash ( invoice. payment_hash ( ) . clone ( ) . into_inner ( ) ) ;
@@ -278,7 +287,8 @@ where
278
287
let payer = self . payer . node_id ( ) ;
279
288
let first_hops = self . payer . first_hops ( ) ;
280
289
let route = self . router . find_route (
281
- & payer, & params, Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) , & self . scorer
290
+ & payer, & params, Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) ,
291
+ & * self . scorer . read ( ) . unwrap ( )
282
292
) . map_err ( |e| PaymentError :: Routing ( e) ) ?;
283
293
self . payer . retry_payment ( & route, payment_id) . map_err ( |e| PaymentError :: Sending ( e) )
284
294
}
@@ -311,7 +321,13 @@ where
311
321
{
312
322
fn handle_event ( & self , event : & Event ) {
313
323
match event {
314
- Event :: PaymentPathFailed { payment_id, payment_hash, rejected_by_dest, retry, .. } => {
324
+ Event :: PaymentPathFailed {
325
+ payment_id, payment_hash, rejected_by_dest, path, short_channel_id, retry, ..
326
+ } => {
327
+ if let Some ( short_channel_id) = short_channel_id {
328
+ self . scorer . write ( ) . unwrap ( ) . payment_path_failed ( path, * short_channel_id) ;
329
+ }
330
+
315
331
let mut payment_cache = self . payment_cache . lock ( ) . unwrap ( ) ;
316
332
let entry = loop {
317
333
let entry = payment_cache. entry ( * payment_hash) ;
@@ -862,6 +878,39 @@ mod tests {
862
878
}
863
879
}
864
880
881
+ #[ test]
882
+ fn scores_failed_channel ( ) {
883
+ let event_handled = core:: cell:: RefCell :: new ( false ) ;
884
+ let event_handler = |_: & _ | { * event_handled. borrow_mut ( ) = true ; } ;
885
+
886
+ let payment_preimage = PaymentPreimage ( [ 1 ; 32 ] ) ;
887
+ let invoice = invoice ( payment_preimage) ;
888
+ let payment_hash = PaymentHash ( invoice. payment_hash ( ) . clone ( ) . into_inner ( ) ) ;
889
+ let final_value_msat = invoice. amount_milli_satoshis ( ) . unwrap ( ) ;
890
+ let path = TestRouter :: path_for_value ( final_value_msat) ;
891
+ let short_channel_id = Some ( path[ 0 ] . short_channel_id ) ;
892
+
893
+ let payer = TestPayer :: new ( ) ;
894
+ let router = TestRouter { } ;
895
+ let scorer = TestScorer :: new ( ) . expect_channel_failure ( short_channel_id. unwrap ( ) ) ;
896
+ let logger = TestLogger :: new ( ) ;
897
+ let invoice_payer =
898
+ InvoicePayer :: new ( & payer, router, scorer, & logger, event_handler, RetryAttempts ( 2 ) ) ;
899
+
900
+ let payment_id = Some ( invoice_payer. pay_invoice ( & invoice) . unwrap ( ) ) ;
901
+ let event = Event :: PaymentPathFailed {
902
+ payment_id,
903
+ payment_hash,
904
+ network_update : None ,
905
+ rejected_by_dest : false ,
906
+ all_paths_failed : false ,
907
+ path,
908
+ short_channel_id,
909
+ retry : Some ( TestRouter :: retry_for_invoice ( & invoice) ) ,
910
+ } ;
911
+ invoice_payer. handle_event ( & event) ;
912
+ }
913
+
865
914
struct TestRouter ;
866
915
867
916
impl TestRouter {
@@ -933,16 +982,45 @@ mod tests {
933
982
}
934
983
}
935
984
936
- struct TestScorer ;
985
+ struct TestScorer {
986
+ expectations : std:: collections:: VecDeque < u64 > ,
987
+ }
937
988
938
989
impl TestScorer {
939
- fn new ( ) -> Self { Self { } }
990
+ fn new ( ) -> Self {
991
+ Self {
992
+ expectations : std:: collections:: VecDeque :: new ( ) ,
993
+ }
994
+ }
995
+
996
+ fn expect_channel_failure ( mut self , short_channel_id : u64 ) -> Self {
997
+ self . expectations . push_back ( short_channel_id) ;
998
+ self
999
+ }
940
1000
}
941
1001
942
1002
impl routing:: Score for TestScorer {
943
1003
fn channel_penalty_msat (
944
1004
& self , _short_channel_id : u64 , _source : & NodeId , _target : & NodeId
945
1005
) -> u64 { 0 }
1006
+
1007
+ fn payment_path_failed ( & mut self , _path : & Vec < RouteHop > , short_channel_id : u64 ) {
1008
+ if let Some ( expected_short_channel_id) = self . expectations . pop_front ( ) {
1009
+ assert_eq ! ( short_channel_id, expected_short_channel_id) ;
1010
+ }
1011
+ }
1012
+ }
1013
+
1014
+ impl Drop for TestScorer {
1015
+ fn drop ( & mut self ) {
1016
+ if std:: thread:: panicking ( ) {
1017
+ return ;
1018
+ }
1019
+
1020
+ if !self . expectations . is_empty ( ) {
1021
+ panic ! ( "Unsatisfied channel failure expectations: {:?}" , self . expectations) ;
1022
+ }
1023
+ }
946
1024
}
947
1025
948
1026
struct TestPayer {
0 commit comments