@@ -285,7 +285,7 @@ impl KeyProvider {
285
285
}
286
286
287
287
#[ inline]
288
- fn check_api_err ( api_err : APIError ) {
288
+ fn check_api_err ( api_err : APIError , sendable_bounds_violated : bool ) {
289
289
match api_err {
290
290
APIError :: APIMisuseError { .. } => panic ! ( "We can't misuse the API" ) ,
291
291
APIError :: FeeRateTooHigh { .. } => panic ! ( "We can't send too much fee?" ) ,
@@ -305,6 +305,7 @@ fn check_api_err(api_err: APIError) {
305
305
_ if err. starts_with ( "Cannot send value that would put our exposure to dust HTLCs at" ) => { } ,
306
306
_ => panic ! ( "{}" , err) ,
307
307
}
308
+ assert ! ( sendable_bounds_violated) ;
308
309
} ,
309
310
APIError :: MonitorUpdateInProgress => {
310
311
// We can (obviously) temp-fail a monitor update
@@ -313,17 +314,17 @@ fn check_api_err(api_err: APIError) {
313
314
}
314
315
}
315
316
#[ inline]
316
- fn check_payment_err ( send_err : PaymentSendFailure ) {
317
+ fn check_payment_err ( send_err : PaymentSendFailure , sendable_bounds_violated : bool ) {
317
318
match send_err {
318
- PaymentSendFailure :: ParameterError ( api_err) => check_api_err ( api_err) ,
319
+ PaymentSendFailure :: ParameterError ( api_err) => check_api_err ( api_err, sendable_bounds_violated ) ,
319
320
PaymentSendFailure :: PathParameterError ( per_path_results) => {
320
- for res in per_path_results { if let Err ( api_err) = res { check_api_err ( api_err) ; } }
321
+ for res in per_path_results { if let Err ( api_err) = res { check_api_err ( api_err, sendable_bounds_violated ) ; } }
321
322
} ,
322
323
PaymentSendFailure :: AllFailedResendSafe ( per_path_results) => {
323
- for api_err in per_path_results { check_api_err ( api_err) ; }
324
+ for api_err in per_path_results { check_api_err ( api_err, sendable_bounds_violated ) ; }
324
325
} ,
325
326
PaymentSendFailure :: PartialFailure { results, .. } => {
326
- for res in results { if let Err ( api_err) = res { check_api_err ( api_err) ; } }
327
+ for res in results { if let Err ( api_err) = res { check_api_err ( api_err, sendable_bounds_violated ) ; } }
327
328
} ,
328
329
PaymentSendFailure :: DuplicatePayment => panic ! ( ) ,
329
330
}
@@ -351,6 +352,11 @@ fn send_payment(source: &ChanMan, dest: &ChanMan, dest_chan_id: u64, amt: u64, p
351
352
let mut payment_id = [ 0 ; 32 ] ;
352
353
payment_id[ 0 ..8 ] . copy_from_slice ( & payment_idx. to_ne_bytes ( ) ) ;
353
354
* payment_idx += 1 ;
355
+ let ( min_value_sendable, max_value_sendable) = source. list_usable_channels ( )
356
+ . iter ( ) . find ( |chan| chan. short_channel_id == Some ( dest_chan_id) )
357
+ . map ( |chan|
358
+ ( chan. next_outbound_htlc_minimum_msat , chan. next_outbound_htlc_limit_msat ) )
359
+ . unwrap_or ( ( 0 , 0 ) ) ;
354
360
if let Err ( err) = source. send_payment_with_route ( & Route {
355
361
paths : vec ! [ Path { hops: vec![ RouteHop {
356
362
pubkey: dest. get_our_node_id( ) ,
@@ -362,9 +368,15 @@ fn send_payment(source: &ChanMan, dest: &ChanMan, dest_chan_id: u64, amt: u64, p
362
368
} ] , blinded_tail: None } ] ,
363
369
payment_params : None ,
364
370
} , payment_hash, RecipientOnionFields :: secret_only ( payment_secret) , PaymentId ( payment_id) ) {
365
- check_payment_err ( err) ;
371
+ check_payment_err ( err, amt > max_value_sendable || amt < min_value_sendable ) ;
366
372
false
367
- } else { true }
373
+ } else {
374
+ // Note that while the max is a strict upper-bound, we can occasionally send substantially
375
+ // below the minimum, with some gap which is unusable immediately below the minimum. Thus,
376
+ // we don't check against min_value_sendable here.
377
+ assert ! ( amt <= max_value_sendable) ;
378
+ true
379
+ }
368
380
}
369
381
#[ inline]
370
382
fn send_hop_payment ( source : & ChanMan , middle : & ChanMan , middle_chan_id : u64 , dest : & ChanMan , dest_chan_id : u64 , amt : u64 , payment_id : & mut u8 , payment_idx : & mut u64 ) -> bool {
@@ -373,13 +385,19 @@ fn send_hop_payment(source: &ChanMan, middle: &ChanMan, middle_chan_id: u64, des
373
385
let mut payment_id = [ 0 ; 32 ] ;
374
386
payment_id[ 0 ..8 ] . copy_from_slice ( & payment_idx. to_ne_bytes ( ) ) ;
375
387
* payment_idx += 1 ;
388
+ let ( min_value_sendable, max_value_sendable) = source. list_usable_channels ( )
389
+ . iter ( ) . find ( |chan| chan. short_channel_id == Some ( middle_chan_id) )
390
+ . map ( |chan|
391
+ ( chan. next_outbound_htlc_minimum_msat , chan. next_outbound_htlc_limit_msat ) )
392
+ . unwrap_or ( ( 0 , 0 ) ) ;
393
+ let first_hop_fee = 50_000 ;
376
394
if let Err ( err) = source. send_payment_with_route ( & Route {
377
395
paths : vec ! [ Path { hops: vec![ RouteHop {
378
396
pubkey: middle. get_our_node_id( ) ,
379
397
node_features: middle. node_features( ) ,
380
398
short_channel_id: middle_chan_id,
381
399
channel_features: middle. channel_features( ) ,
382
- fee_msat: 50000 ,
400
+ fee_msat: first_hop_fee ,
383
401
cltv_expiry_delta: 100 ,
384
402
} , RouteHop {
385
403
pubkey: dest. get_our_node_id( ) ,
@@ -391,9 +409,16 @@ fn send_hop_payment(source: &ChanMan, middle: &ChanMan, middle_chan_id: u64, des
391
409
} ] , blinded_tail: None } ] ,
392
410
payment_params : None ,
393
411
} , payment_hash, RecipientOnionFields :: secret_only ( payment_secret) , PaymentId ( payment_id) ) {
394
- check_payment_err ( err) ;
412
+ let sent_amt = amt + first_hop_fee;
413
+ check_payment_err ( err, sent_amt < min_value_sendable || sent_amt > max_value_sendable) ;
395
414
false
396
- } else { true }
415
+ } else {
416
+ // Note that while the max is a strict upper-bound, we can occasionally send substantially
417
+ // below the minimum, with some gap which is unusable immediately below the minimum. Thus,
418
+ // we don't check against min_value_sendable here.
419
+ assert ! ( amt + first_hop_fee <= max_value_sendable) ;
420
+ true
421
+ }
397
422
}
398
423
399
424
#[ inline]
0 commit comments