@@ -981,23 +981,19 @@ fn do_multi_hop_receiver_fail(check: ReceiveCheckFail) {
981981 } ;
982982
983983 let amt_msat = 5000 ;
984- let excess_final_cltv_delta_opt = if check == ReceiveCheckFail :: ProcessPendingHTLCsCheck {
985- // Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
986- Some ( TEST_FINAL_CLTV as u16 - 2 )
984+ let required_final_cltv = if check == ReceiveCheckFail :: ProcessPendingHTLCsCheck {
985+ // Set the final CLTV required much too high to trigger the failure in process_pending_htlc_forwards.
986+ Some ( ( TEST_FINAL_CLTV as u16 ) * 10 )
987987 } else { None } ;
988- let ( _, payment_hash, payment_secret) = get_payment_preimage_hash ( & nodes[ 2 ] , Some ( amt_msat) , excess_final_cltv_delta_opt ) ;
988+ let ( _, payment_hash, payment_secret) = get_payment_preimage_hash ( & nodes[ 2 ] , Some ( amt_msat) , required_final_cltv ) ;
989989 let mut route_params = get_blinded_route_parameters ( amt_msat, payment_secret, 1 , 1_0000_0000 ,
990990 nodes. iter ( ) . skip ( 1 ) . map ( |n| n. node . get_our_node_id ( ) ) . collect ( ) , & [ & chan_upd_1_2] ,
991991 & chanmon_cfgs[ 2 ] . keys_manager ) ;
992992
993993 route_params. payment_params . max_path_length = 17 ;
994994
995995 let route = if check == ReceiveCheckFail :: ProcessPendingHTLCsCheck {
996- let mut route = get_route ( & nodes[ 0 ] , & route_params) . unwrap ( ) ;
997- // Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
998- route. paths [ 0 ] . hops . last_mut ( ) . map ( |h| h. cltv_expiry_delta += excess_final_cltv_delta_opt. unwrap ( ) as u32 ) ;
999- route. paths [ 0 ] . blinded_tail . as_mut ( ) . map ( |bt| bt. excess_final_cltv_expiry_delta = excess_final_cltv_delta_opt. unwrap ( ) as u32 ) ;
1000- route
996+ get_route ( & nodes[ 0 ] , & route_params) . unwrap ( )
1001997 } else if check == ReceiveCheckFail :: PaymentConstraints {
1002998 // Create a blinded path where the receiver's encrypted payload has an htlc_minimum_msat that is
1003999 // violated by `amt_msat`, and stick it in the route_params without changing the corresponding
@@ -1115,7 +1111,6 @@ fn do_multi_hop_receiver_fail(check: ReceiveCheckFail) {
11151111 check_added_monitors ( & nodes[ 2 ] , 1 ) ;
11161112 } ,
11171113 ReceiveCheckFail :: ProcessPendingHTLCsCheck => {
1118- assert_eq ! ( payment_event_1_2. msgs[ 0 ] . cltv_expiry, nodes[ 0 ] . best_block_info( ) . 1 + 1 + excess_final_cltv_delta_opt. unwrap( ) as u32 + TEST_FINAL_CLTV ) ;
11191114 nodes[ 2 ] . node . handle_update_add_htlc ( nodes[ 1 ] . node . get_our_node_id ( ) , & payment_event_1_2. msgs [ 0 ] ) ;
11201115 check_added_monitors ( & nodes[ 2 ] , 0 ) ;
11211116 do_commitment_signed_dance ( & nodes[ 2 ] , & nodes[ 1 ] , & payment_event_1_2. commitment_msg , true , true ) ;
@@ -1857,7 +1852,7 @@ fn test_combined_trampoline_onion_creation_vectors() {
18571852 short_channel_id: ( 572330 << 40 ) + ( 42 << 16 ) + 2821 ,
18581853 channel_features: ChannelFeatures :: empty( ) ,
18591854 fee_msat: 153_000 ,
1860- cltv_expiry_delta: 0 ,
1855+ cltv_expiry_delta: 24 + 36 ,
18611856 maybe_announced_channel: false ,
18621857 } ,
18631858 ] ,
@@ -1952,7 +1947,7 @@ fn test_trampoline_inbound_payment_decoding() {
19521947 short_channel_id: ( 572330 << 40 ) + ( 42 << 16 ) + 2821 ,
19531948 channel_features: ChannelFeatures :: empty( ) ,
19541949 fee_msat: 150_153_000 ,
1955- cltv_expiry_delta: 0 ,
1950+ cltv_expiry_delta: 24 + 36 ,
19561951 maybe_announced_channel: false ,
19571952 } ,
19581953 ] ,
@@ -2120,7 +2115,7 @@ fn test_trampoline_forward_payload_encoded_as_receive() {
21202115 blinded_path:: utils:: construct_blinded_hops (
21212116 & secp_ctx, path. into_iter ( ) , & trampoline_session_priv,
21222117 )
2123- } ;
2118+ } ;
21242119
21252120 let route = Route {
21262121 paths : vec ! [ Path {
@@ -2143,7 +2138,7 @@ fn test_trampoline_forward_payload_encoded_as_receive() {
21432138 short_channel_id: bob_carol_scid,
21442139 channel_features: ChannelFeatures :: empty( ) ,
21452140 fee_msat: 0 ,
2146- cltv_expiry_delta: 48 ,
2141+ cltv_expiry_delta: 24 + 39 ,
21472142 maybe_announced_channel: false ,
21482143 }
21492144 ] ,
@@ -2154,7 +2149,7 @@ fn test_trampoline_forward_payload_encoded_as_receive() {
21542149 pubkey: carol_node_id,
21552150 node_features: Features :: empty( ) ,
21562151 fee_msat: amt_msat,
2157- cltv_expiry_delta: 24 ,
2152+ cltv_expiry_delta: 24 + 39 ,
21582153 } ,
21592154 ] ,
21602155 hops: carol_blinded_hops,
@@ -2181,7 +2176,7 @@ fn test_trampoline_forward_payload_encoded_as_receive() {
21812176 } ) ;
21822177
21832178 let recipient_onion_fields = RecipientOnionFields :: spontaneous_empty ( amt_msat) ;
2184- let ( mut trampoline_payloads, outer_total_msat, outer_starting_htlc_offset ) = onion_utils:: build_trampoline_onion_payloads ( & blinded_tail, & recipient_onion_fields, 32 , & None ) . unwrap ( ) ;
2179+ let ( mut trampoline_payloads, outer_total_msat) = onion_utils:: build_trampoline_onion_payloads ( & blinded_tail, & recipient_onion_fields, 32 , & None ) . unwrap ( ) ;
21852180
21862181 // pop the last dummy hop
21872182 trampoline_payloads. pop ( ) ;
@@ -2196,7 +2191,7 @@ fn test_trampoline_forward_payload_encoded_as_receive() {
21962191 ) . unwrap ( ) ;
21972192
21982193 let recipient_onion_fields = RecipientOnionFields :: spontaneous_empty ( outer_total_msat) ;
2199- let ( outer_payloads, _, _) = onion_utils:: test_build_onion_payloads ( & route. paths [ 0 ] , & recipient_onion_fields, outer_starting_htlc_offset , & None , None , Some ( trampoline_packet) ) . unwrap ( ) ;
2194+ let ( outer_payloads, _, _) = onion_utils:: test_build_onion_payloads ( & route. paths [ 0 ] , & recipient_onion_fields, 32 , & None , None , Some ( trampoline_packet) ) . unwrap ( ) ;
22002195 let outer_onion_keys = onion_utils:: construct_onion_keys ( & secp_ctx, & route. clone ( ) . paths [ 0 ] , & outer_session_priv) ;
22012196 let outer_packet = onion_utils:: construct_onion_packet (
22022197 outer_payloads,
@@ -2309,7 +2304,7 @@ fn do_test_trampoline_single_hop_receive(success: bool) {
23092304 short_channel_id: bob_carol_scid,
23102305 channel_features: ChannelFeatures :: empty( ) ,
23112306 fee_msat: 0 ,
2312- cltv_expiry_delta: 48 ,
2307+ cltv_expiry_delta: 104 + 39 ,
23132308 maybe_announced_channel: false ,
23142309 }
23152310 ] ,
@@ -2320,7 +2315,7 @@ fn do_test_trampoline_single_hop_receive(success: bool) {
23202315 pubkey: carol_node_id,
23212316 node_features: Features :: empty( ) ,
23222317 fee_msat: amt_msat,
2323- cltv_expiry_delta: 104 ,
2318+ cltv_expiry_delta: 104 + 39 ,
23242319 } ,
23252320 ] ,
23262321 hops: blinded_path. blinded_hops( ) . to_vec( ) ,
@@ -2428,8 +2423,8 @@ fn test_trampoline_blinded_receive() {
24282423/// Creates a blinded tail where Carol receives via a blinded path.
24292424fn create_blinded_tail (
24302425 secp_ctx : & Secp256k1 < All > , override_random_bytes : [ u8 ; 32 ] , carol_node_id : PublicKey ,
2431- carol_auth_key : ReceiveAuthKey , trampoline_cltv_expiry_delta : u32 , final_value_msat : u64 ,
2432- payment_secret : PaymentSecret ,
2426+ carol_auth_key : ReceiveAuthKey , trampoline_cltv_expiry_delta : u32 ,
2427+ excess_final_cltv_delta : u32 , final_value_msat : u64 , payment_secret : PaymentSecret ,
24332428) -> BlindedTail {
24342429 let outer_session_priv = SecretKey :: from_slice ( & override_random_bytes) . unwrap ( ) ;
24352430 let trampoline_session_priv = onion_utils:: compute_trampoline_session_priv ( & outer_session_priv) ;
@@ -2460,11 +2455,11 @@ fn create_blinded_tail(
24602455 pubkey: carol_node_id,
24612456 node_features: Features :: empty( ) ,
24622457 fee_msat: final_value_msat,
2463- cltv_expiry_delta: trampoline_cltv_expiry_delta,
2458+ cltv_expiry_delta: trampoline_cltv_expiry_delta + excess_final_cltv_delta ,
24642459 } ] ,
24652460 hops : carol_blinded_hops,
24662461 blinding_point : carol_blinding_point,
2467- excess_final_cltv_expiry_delta : 39 ,
2462+ excess_final_cltv_expiry_delta : excess_final_cltv_delta ,
24682463 final_value_msat,
24692464 }
24702465}
@@ -2473,8 +2468,9 @@ fn create_blinded_tail(
24732468// payloads that send to unblinded receives and invalid payloads.
24742469fn replacement_onion (
24752470 test_case : TrampolineTestCase , secp_ctx : & Secp256k1 < All > , override_random_bytes : [ u8 ; 32 ] ,
2476- route : Route , original_amt_msat : u64 , starting_htlc_offset : u32 , original_trampoline_cltv : u32 ,
2477- payment_hash : PaymentHash , payment_secret : PaymentSecret , blinded : bool ,
2471+ route : Route , original_amt_msat : u64 , starting_htlc_offset : u32 , excess_final_cltv : u32 ,
2472+ original_trampoline_cltv : u32 , payment_hash : PaymentHash , payment_secret : PaymentSecret ,
2473+ blinded : bool ,
24782474) -> msgs:: OnionPacket {
24792475 let outer_session_priv = SecretKey :: from_slice ( & override_random_bytes[ ..] ) . unwrap ( ) ;
24802476 let trampoline_session_priv = onion_utils:: compute_trampoline_session_priv ( & outer_session_priv) ;
@@ -2485,8 +2481,8 @@ fn replacement_onion(
24852481 // Rebuild our trampoline packet from the original route. If we want to test Carol receiving
24862482 // as an unblinded trampoline hop, we switch out her inner trampoline onion with a direct
24872483 // receive payload because LDK doesn't support unblinded trampoline receives.
2488- let ( trampoline_packet, outer_total_msat, outer_starting_htlc_offset ) = {
2489- let ( mut trampoline_payloads, outer_total_msat, outer_starting_htlc_offset ) =
2484+ let ( trampoline_packet, outer_total_msat) = {
2485+ let ( mut trampoline_payloads, outer_total_msat) =
24902486 onion_utils:: build_trampoline_onion_payloads (
24912487 & blinded_tail,
24922488 & recipient_onion_fields,
@@ -2502,7 +2498,9 @@ fn replacement_onion(
25022498 total_msat: original_amt_msat,
25032499 } ) ,
25042500 sender_intended_htlc_amt_msat: original_amt_msat,
2505- cltv_expiry_height: original_trampoline_cltv + starting_htlc_offset,
2501+ cltv_expiry_height: original_trampoline_cltv
2502+ + starting_htlc_offset
2503+ + excess_final_cltv,
25062504 } ] ;
25072505 }
25082506
@@ -2520,7 +2518,7 @@ fn replacement_onion(
25202518 )
25212519 . unwrap ( ) ;
25222520
2523- ( trampoline_packet, outer_total_msat, outer_starting_htlc_offset )
2521+ ( trampoline_packet, outer_total_msat)
25242522 } ;
25252523
25262524 // Use a different session key to construct the replacement onion packet. Note that the
@@ -2529,7 +2527,7 @@ fn replacement_onion(
25292527 let ( mut outer_payloads, _, _) = onion_utils:: test_build_onion_payloads (
25302528 & route. paths [ 0 ] ,
25312529 & recipient_onion_fields,
2532- outer_starting_htlc_offset ,
2530+ starting_htlc_offset ,
25332531 & None ,
25342532 None ,
25352533 Some ( trampoline_packet) ,
@@ -2547,7 +2545,7 @@ fn replacement_onion(
25472545 ..
25482546 } => {
25492547 * amt_to_forward = test_case. outer_onion_amt ( original_amt_msat) ;
2550- let outer_cltv = original_trampoline_cltv + starting_htlc_offset;
2548+ let outer_cltv = original_trampoline_cltv + starting_htlc_offset + excess_final_cltv ;
25512549 * outgoing_cltv_value = test_case. outer_onion_cltv ( outer_cltv) ;
25522550 } ,
25532551 _ => panic ! ( "final payload is not trampoline entrypoint" ) ,
@@ -2582,11 +2580,9 @@ fn do_test_trampoline_relay(blinded: bool, test_case: TrampolineTestCase) {
25822580 let alice_bob_chan = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 ) ;
25832581 let bob_carol_chan = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 1_000_000 , 0 ) ;
25842582
2583+ let starting_htlc_offset = ( TOTAL_NODE_COUNT as u32 ) * CHAN_CONFIRM_DEPTH + 1 ;
25852584 for i in 0 ..TOTAL_NODE_COUNT {
2586- connect_blocks (
2587- & nodes[ i] ,
2588- ( TOTAL_NODE_COUNT as u32 ) * CHAN_CONFIRM_DEPTH + 1 - nodes[ i] . best_block_info ( ) . 1 ,
2589- ) ;
2585+ connect_blocks ( & nodes[ i] , starting_htlc_offset - nodes[ i] . best_block_info ( ) . 1 ) ;
25902586 }
25912587
25922588 let alice_node_id = nodes[ 0 ] . node . get_our_node_id ( ) ;
@@ -2597,8 +2593,11 @@ fn do_test_trampoline_relay(blinded: bool, test_case: TrampolineTestCase) {
25972593 let bob_carol_scid = get_scid_from_channel_id ( & nodes[ 1 ] , bob_carol_chan. 2 ) ;
25982594
25992595 let original_amt_msat = 1000 ;
2600- let original_trampoline_cltv = 72 ;
2601- let starting_htlc_offset = 32 ;
2596+ // Note that for TrampolineTestCase::OuterCLTVLessThanTrampoline to work properly,
2597+ // (starting_htlc_offset + excess_final_cltv) / 2 < (starting_htlc_offset + excess_final_cltv + original_trampoline_cltv)
2598+ // otherwise dividing the CLTV value by 2 won't kick us under the outer trampoline CLTV.
2599+ let original_trampoline_cltv = 42 ;
2600+ let excess_final_cltv = 70 ;
26022601
26032602 let ( payment_preimage, payment_hash, payment_secret) =
26042603 get_payment_preimage_hash ( & nodes[ 2 ] , Some ( original_amt_msat) , None ) ;
@@ -2625,7 +2624,7 @@ fn do_test_trampoline_relay(blinded: bool, test_case: TrampolineTestCase) {
26252624 short_channel_id: bob_carol_scid,
26262625 channel_features: ChannelFeatures :: empty( ) ,
26272626 fee_msat: 0 ,
2628- cltv_expiry_delta: 48 ,
2627+ cltv_expiry_delta: original_trampoline_cltv + excess_final_cltv ,
26292628 maybe_announced_channel: false ,
26302629 } ,
26312630 ] ,
@@ -2638,6 +2637,7 @@ fn do_test_trampoline_relay(blinded: bool, test_case: TrampolineTestCase) {
26382637 carol_node_id,
26392638 nodes[ 2 ] . keys_manager. get_receive_auth_key( ) ,
26402639 original_trampoline_cltv,
2640+ excess_final_cltv,
26412641 original_amt_msat,
26422642 payment_secret,
26432643 ) ) ,
@@ -2680,6 +2680,7 @@ fn do_test_trampoline_relay(blinded: bool, test_case: TrampolineTestCase) {
26802680 original_amt_msat,
26812681 starting_htlc_offset,
26822682 original_trampoline_cltv,
2683+ excess_final_cltv,
26832684 payment_hash,
26842685 payment_secret,
26852686 blinded,
@@ -2696,8 +2697,9 @@ fn do_test_trampoline_relay(blinded: bool, test_case: TrampolineTestCase) {
26962697 ) ;
26972698
26982699 let amt_bytes = test_case. outer_onion_amt ( original_amt_msat) . to_be_bytes ( ) ;
2699- let cltv_bytes =
2700- test_case. outer_onion_cltv ( original_trampoline_cltv + starting_htlc_offset) . to_be_bytes ( ) ;
2700+ let cltv_bytes = test_case
2701+ . outer_onion_cltv ( original_trampoline_cltv + starting_htlc_offset + excess_final_cltv)
2702+ . to_be_bytes ( ) ;
27012703 let payment_failure = test_case. payment_failed_conditions ( & amt_bytes, & cltv_bytes) . map ( |p| {
27022704 if blinded {
27032705 PaymentFailedConditions :: new ( )
@@ -2711,7 +2713,8 @@ fn do_test_trampoline_relay(blinded: bool, test_case: TrampolineTestCase) {
27112713 . without_claimable_event ( )
27122714 . expect_failure ( HTLCHandlingFailureType :: Receive { payment_hash } )
27132715 } else {
2714- args. with_payment_secret ( payment_secret)
2716+ let htlc_cltv = starting_htlc_offset + original_trampoline_cltv + excess_final_cltv;
2717+ args. with_payment_secret ( payment_secret) . with_payment_claimable_cltv ( htlc_cltv)
27152718 } ;
27162719
27172720 do_pass_along_path ( args) ;
@@ -2797,7 +2800,7 @@ fn test_trampoline_forward_rejection() {
27972800 short_channel_id: bob_carol_scid,
27982801 channel_features: ChannelFeatures :: empty( ) ,
27992802 fee_msat: 0 ,
2800- cltv_expiry_delta: 48 ,
2803+ cltv_expiry_delta: 24 + 24 + 39 ,
28012804 maybe_announced_channel: false ,
28022805 }
28032806 ] ,
@@ -2816,7 +2819,7 @@ fn test_trampoline_forward_rejection() {
28162819 pubkey: alice_node_id,
28172820 node_features: Features :: empty( ) ,
28182821 fee_msat: amt_msat,
2819- cltv_expiry_delta: 24 ,
2822+ cltv_expiry_delta: 24 + 39 ,
28202823 } ,
28212824 ] ,
28222825 hops: vec![ BlindedHop {
0 commit comments