@@ -459,12 +459,28 @@ fn two_hop_blinded_path_success() {
459459 claim_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] , & nodes[ 2 ] ] , payment_preimage) ;
460460}
461461
462+ enum ReceiveCheckFail {
463+ // The recipient fails the payment upon `PaymentClaimable`.
464+ RecipientFail ,
465+ // Failure to decode the recipient's onion payload.
466+ OnionDecodeFail ,
467+ }
468+
462469#[ test]
463470fn multi_hop_receiver_fail ( ) {
471+ do_multi_hop_receiver_fail ( ReceiveCheckFail :: RecipientFail ) ;
472+ do_multi_hop_receiver_fail ( ReceiveCheckFail :: OnionDecodeFail ) ;
473+ }
474+
475+ fn do_multi_hop_receiver_fail ( check : ReceiveCheckFail ) {
476+ // Test that the receiver to a multihop blinded path fails back correctly.
464477 let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
465478 let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
466479 let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
467480 let mut nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
481+ // We need the session priv to construct an invalid onion packet later.
482+ let session_priv = [ 3 ; 32 ] ;
483+ * nodes[ 0 ] . keys_manager . override_random_bytes . lock ( ) . unwrap ( ) = Some ( session_priv) ;
468484 create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 ) ;
469485 let chan_upd_1_2 = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 1_000_000 , 0 ) . 0 . contents ;
470486
@@ -478,14 +494,68 @@ fn multi_hop_receiver_fail() {
478494 node_cfgs[ 0 ] . router . expect_find_route ( route_params. clone ( ) , Ok ( route. clone ( ) ) ) ;
479495 nodes[ 0 ] . node . send_payment ( payment_hash, RecipientOnionFields :: spontaneous_empty ( ) , PaymentId ( payment_hash. 0 ) , route_params, Retry :: Attempts ( 0 ) ) . unwrap ( ) ;
480496 check_added_monitors ( & nodes[ 0 ] , 1 ) ;
481- pass_along_route ( & nodes[ 0 ] , & [ & [ & nodes[ 1 ] , & nodes[ 2 ] ] ] , amt_msat, payment_hash, payment_secret) ;
482497
483- nodes[ 2 ] . node . fail_htlc_backwards ( & payment_hash) ;
484- expect_pending_htlcs_forwardable_conditions (
485- nodes[ 2 ] . node . get_and_clear_pending_events ( ) , & [ HTLCDestination :: FailedPayment { payment_hash } ]
486- ) ;
487- nodes[ 2 ] . node . process_pending_htlc_forwards ( ) ;
488- check_added_monitors ! ( nodes[ 2 ] , 1 ) ;
498+ let mut payment_event_0_1 = {
499+ let mut events = nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) ;
500+ assert_eq ! ( events. len( ) , 1 ) ;
501+ let ev = remove_first_msg_event_to_node ( & nodes[ 1 ] . node . get_our_node_id ( ) , & mut events) ;
502+ SendEvent :: from_event ( ev)
503+ } ;
504+ nodes[ 1 ] . node . handle_update_add_htlc ( & nodes[ 0 ] . node . get_our_node_id ( ) , & payment_event_0_1. msgs [ 0 ] ) ;
505+ check_added_monitors ! ( nodes[ 1 ] , 0 ) ;
506+ do_commitment_signed_dance ( & nodes[ 1 ] , & nodes[ 0 ] , & payment_event_0_1. commitment_msg , false , false ) ;
507+ expect_pending_htlcs_forwardable ! ( nodes[ 1 ] ) ;
508+ check_added_monitors ! ( & nodes[ 1 ] , 1 ) ;
509+
510+ let mut payment_event_1_2 = {
511+ let mut events = nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
512+ assert_eq ! ( events. len( ) , 1 ) ;
513+ let ev = remove_first_msg_event_to_node ( & nodes[ 2 ] . node . get_our_node_id ( ) , & mut events) ;
514+ SendEvent :: from_event ( ev)
515+ } ;
516+
517+ match check {
518+ ReceiveCheckFail :: RecipientFail => {
519+ nodes[ 2 ] . node . handle_update_add_htlc ( & nodes[ 1 ] . node . get_our_node_id ( ) , & payment_event_1_2. msgs [ 0 ] ) ;
520+ check_added_monitors ! ( nodes[ 2 ] , 0 ) ;
521+ do_commitment_signed_dance ( & nodes[ 2 ] , & nodes[ 1 ] , & payment_event_1_2. commitment_msg , true , true ) ;
522+ expect_pending_htlcs_forwardable ! ( nodes[ 2 ] ) ;
523+ check_payment_claimable (
524+ & nodes[ 2 ] . node . get_and_clear_pending_events ( ) [ 0 ] , payment_hash, payment_secret, amt_msat,
525+ None , nodes[ 2 ] . node . get_our_node_id ( )
526+ ) ;
527+ nodes[ 2 ] . node . fail_htlc_backwards ( & payment_hash) ;
528+ expect_pending_htlcs_forwardable_conditions (
529+ nodes[ 2 ] . node . get_and_clear_pending_events ( ) , & [ HTLCDestination :: FailedPayment { payment_hash } ]
530+ ) ;
531+ nodes[ 2 ] . node . process_pending_htlc_forwards ( ) ;
532+ check_added_monitors ! ( nodes[ 2 ] , 1 ) ;
533+ } ,
534+ ReceiveCheckFail :: OnionDecodeFail => {
535+ let session_priv = SecretKey :: from_slice ( & session_priv) . unwrap ( ) ;
536+ let mut onion_keys = onion_utils:: construct_onion_keys ( & Secp256k1 :: new ( ) , & route. paths [ 0 ] , & session_priv) . unwrap ( ) ;
537+ let cur_height = nodes[ 0 ] . best_block_info ( ) . 1 ;
538+ let ( mut onion_payloads, ..) = onion_utils:: build_onion_payloads (
539+ & route. paths [ 0 ] , amt_msat, RecipientOnionFields :: spontaneous_empty ( ) , cur_height, & None ) . unwrap ( ) ;
540+
541+ let update_add = & mut payment_event_1_2. msgs [ 0 ] ;
542+ onion_payloads. last_mut ( ) . map ( |p| {
543+ if let msgs:: OutboundOnionPayload :: BlindedReceive { ref mut intro_node_blinding_point, .. } = p {
544+ // The receiver should error if both the update_add blinding_point and the
545+ // intro_node_blinding_point are set.
546+ assert ! ( intro_node_blinding_point. is_none( ) && update_add. blinding_point. is_some( ) ) ;
547+ * intro_node_blinding_point = Some ( PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ) ;
548+ } else { panic ! ( ) }
549+ } ) ;
550+ update_add. onion_routing_packet = onion_utils:: construct_onion_packet (
551+ vec ! [ onion_payloads. pop( ) . unwrap( ) ] , vec ! [ onion_keys. pop( ) . unwrap( ) ] , [ 0 ; 32 ] ,
552+ & payment_hash
553+ ) . unwrap ( ) ;
554+ nodes[ 2 ] . node . handle_update_add_htlc ( & nodes[ 1 ] . node . get_our_node_id ( ) , update_add) ;
555+ check_added_monitors ! ( nodes[ 2 ] , 0 ) ;
556+ do_commitment_signed_dance ( & nodes[ 2 ] , & nodes[ 1 ] , & payment_event_1_2. commitment_msg , true , true ) ;
557+ }
558+ }
489559
490560 let updates_2_1 = get_htlc_update_msgs ! ( nodes[ 2 ] , nodes[ 1 ] . node. get_our_node_id( ) ) ;
491561 assert_eq ! ( updates_2_1. update_fail_malformed_htlcs. len( ) , 1 ) ;
0 commit comments