15
15
//! and payee using information provided by the payer and from the payee's [`Invoice`], when
16
16
//! applicable.
17
17
//!
18
+ //! [`InvoicePayer`] is parameterized by a [`LockableScore`], which it uses for scoring failed and
19
+ //! successful payment paths upon receiving [`Event::PaymentPathFailed`] and
20
+ //! [`Event::PaymentPathSuccessful`] events, respectively.
21
+ //!
18
22
//! [`InvoicePayer`] is capable of retrying failed payments. It accomplishes this by implementing
19
23
//! [`EventHandler`] which decorates a user-provided handler. It will intercept any
20
24
//! [`Event::PaymentPathFailed`] events and retry the failed paths for a fixed number of total
80
84
//! # &self, _short_channel_id: u64, _send_amt: u64, _chan_amt: Option<u64>, _source: &NodeId, _target: &NodeId
81
85
//! # ) -> u64 { 0 }
82
86
//! # fn payment_path_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {}
87
+ //! # fn payment_path_successful(&mut self, _path: &[&RouteHop]) {}
83
88
//! # }
84
89
//! #
85
90
//! # struct FakeLogger {};
@@ -139,6 +144,10 @@ use std::sync::Mutex;
139
144
use std:: time:: { Duration , SystemTime } ;
140
145
141
146
/// A utility for paying [`Invoice`]s and sending spontaneous payments.
147
+ ///
148
+ /// See [module-level documentation] for details.
149
+ ///
150
+ /// [module-level documentation]: crate::payment
142
151
pub struct InvoicePayer < P : Deref , R , S : Deref , L : Deref , E >
143
152
where
144
153
P :: Target : Payer ,
@@ -473,6 +482,10 @@ where
473
482
474
483
if * all_paths_failed { self . payment_cache . lock ( ) . unwrap ( ) . remove ( payment_hash) ; }
475
484
} ,
485
+ Event :: PaymentPathSuccessful { path, .. } => {
486
+ let path = path. iter ( ) . collect :: < Vec < _ > > ( ) ;
487
+ self . scorer . lock ( ) . payment_path_successful ( & path) ;
488
+ } ,
476
489
Event :: PaymentSent { payment_hash, .. } => {
477
490
let mut payment_cache = self . payment_cache . lock ( ) . unwrap ( ) ;
478
491
let attempts = payment_cache
@@ -1127,7 +1140,9 @@ mod tests {
1127
1140
. expect_send ( Amount :: ForInvoice ( final_value_msat) )
1128
1141
. expect_send ( Amount :: OnRetry ( final_value_msat / 2 ) ) ;
1129
1142
let router = TestRouter { } ;
1130
- let scorer = RefCell :: new ( TestScorer :: new ( ) . expect_channel_failure ( short_channel_id. unwrap ( ) ) ) ;
1143
+ let scorer = RefCell :: new ( TestScorer :: new ( ) . expect ( PaymentPath :: Failure {
1144
+ path : path. clone ( ) , short_channel_id : path[ 0 ] . short_channel_id ,
1145
+ } ) ) ;
1131
1146
let logger = TestLogger :: new ( ) ;
1132
1147
let invoice_payer =
1133
1148
InvoicePayer :: new ( & payer, router, & scorer, & logger, event_handler, RetryAttempts ( 2 ) ) ;
@@ -1146,6 +1161,39 @@ mod tests {
1146
1161
invoice_payer. handle_event ( & event) ;
1147
1162
}
1148
1163
1164
+ #[ test]
1165
+ fn scores_successful_channels ( ) {
1166
+ let event_handled = core:: cell:: RefCell :: new ( false ) ;
1167
+ let event_handler = |_: & _ | { * event_handled. borrow_mut ( ) = true ; } ;
1168
+
1169
+ let payment_preimage = PaymentPreimage ( [ 1 ; 32 ] ) ;
1170
+ let invoice = invoice ( payment_preimage) ;
1171
+ let payment_hash = Some ( PaymentHash ( invoice. payment_hash ( ) . clone ( ) . into_inner ( ) ) ) ;
1172
+ let final_value_msat = invoice. amount_milli_satoshis ( ) . unwrap ( ) ;
1173
+ let route = TestRouter :: route_for_value ( final_value_msat) ;
1174
+
1175
+ // Expect that scorer is given short_channel_id upon handling the event.
1176
+ let payer = TestPayer :: new ( ) . expect_send ( Amount :: ForInvoice ( final_value_msat) ) ;
1177
+ let router = TestRouter { } ;
1178
+ let scorer = RefCell :: new ( TestScorer :: new ( )
1179
+ . expect ( PaymentPath :: Success { path : route. paths [ 0 ] . clone ( ) } )
1180
+ . expect ( PaymentPath :: Success { path : route. paths [ 1 ] . clone ( ) } )
1181
+ ) ;
1182
+ let logger = TestLogger :: new ( ) ;
1183
+ let invoice_payer =
1184
+ InvoicePayer :: new ( & payer, router, & scorer, & logger, event_handler, RetryAttempts ( 2 ) ) ;
1185
+
1186
+ let payment_id = invoice_payer. pay_invoice ( & invoice) . unwrap ( ) ;
1187
+ let event = Event :: PaymentPathSuccessful {
1188
+ payment_id, payment_hash, path : route. paths [ 0 ] . clone ( )
1189
+ } ;
1190
+ invoice_payer. handle_event ( & event) ;
1191
+ let event = Event :: PaymentPathSuccessful {
1192
+ payment_id, payment_hash, path : route. paths [ 1 ] . clone ( )
1193
+ } ;
1194
+ invoice_payer. handle_event ( & event) ;
1195
+ }
1196
+
1149
1197
struct TestRouter ;
1150
1198
1151
1199
impl TestRouter {
@@ -1212,7 +1260,13 @@ mod tests {
1212
1260
}
1213
1261
1214
1262
struct TestScorer {
1215
- expectations : VecDeque < u64 > ,
1263
+ expectations : VecDeque < PaymentPath > ,
1264
+ }
1265
+
1266
+ #[ derive( Debug ) ]
1267
+ enum PaymentPath {
1268
+ Failure { path : Vec < RouteHop > , short_channel_id : u64 } ,
1269
+ Success { path : Vec < RouteHop > } ,
1216
1270
}
1217
1271
1218
1272
impl TestScorer {
@@ -1222,8 +1276,8 @@ mod tests {
1222
1276
}
1223
1277
}
1224
1278
1225
- fn expect_channel_failure ( mut self , short_channel_id : u64 ) -> Self {
1226
- self . expectations . push_back ( short_channel_id ) ;
1279
+ fn expect ( mut self , expectation : PaymentPath ) -> Self {
1280
+ self . expectations . push_back ( expectation ) ;
1227
1281
self
1228
1282
}
1229
1283
}
@@ -1232,14 +1286,36 @@ mod tests {
1232
1286
impl lightning:: util:: ser:: Writeable for TestScorer {
1233
1287
fn write < W : lightning:: util:: ser:: Writer > ( & self , _: & mut W ) -> Result < ( ) , std:: io:: Error > { unreachable ! ( ) ; }
1234
1288
}
1289
+
1235
1290
impl Score for TestScorer {
1236
1291
fn channel_penalty_msat (
1237
1292
& self , _short_channel_id : u64 , _send_amt : u64 , _chan_amt : Option < u64 > , _source : & NodeId , _target : & NodeId
1238
1293
) -> u64 { 0 }
1239
1294
1240
- fn payment_path_failed ( & mut self , _path : & [ & RouteHop ] , short_channel_id : u64 ) {
1241
- if let Some ( expected_short_channel_id) = self . expectations . pop_front ( ) {
1242
- assert_eq ! ( short_channel_id, expected_short_channel_id) ;
1295
+ fn payment_path_failed ( & mut self , actual_path : & [ & RouteHop ] , actual_short_channel_id : u64 ) {
1296
+ if let Some ( expectation) = self . expectations . pop_front ( ) {
1297
+ match expectation {
1298
+ PaymentPath :: Failure { path, short_channel_id } => {
1299
+ assert_eq ! ( actual_path, path. iter( ) . collect:: <Vec <_>>( ) ) ;
1300
+ assert_eq ! ( actual_short_channel_id, short_channel_id) ;
1301
+ } ,
1302
+ PaymentPath :: Success { path } => {
1303
+ panic ! ( "Unexpected successful payment path: {:?}" , path)
1304
+ } ,
1305
+ }
1306
+ }
1307
+ }
1308
+
1309
+ fn payment_path_successful ( & mut self , actual_path : & [ & RouteHop ] ) {
1310
+ if let Some ( expectation) = self . expectations . pop_front ( ) {
1311
+ match expectation {
1312
+ PaymentPath :: Failure { path, .. } => {
1313
+ panic ! ( "Unexpected payment path failure: {:?}" , path)
1314
+ } ,
1315
+ PaymentPath :: Success { path } => {
1316
+ assert_eq ! ( actual_path, path. iter( ) . collect:: <Vec <_>>( ) ) ;
1317
+ } ,
1318
+ }
1243
1319
}
1244
1320
}
1245
1321
}
0 commit comments