@@ -405,6 +405,9 @@ where
405405 > (
406406 & self , recipient : PublicKey , peers : I , secp_ctx : & Secp256k1 < T > , compact_paths : bool
407407 ) -> Result < Vec < BlindedPath > , ( ) > {
408+ let entropy_source = & * self . entropy_source ;
409+ let recipient_node_id = NodeId :: from_pubkey ( & recipient) ;
410+
408411 // Limit the number of blinded paths that are computed.
409412 const MAX_PATHS : usize = 3 ;
410413
@@ -417,40 +420,67 @@ where
417420 network_graph. nodes ( ) . contains_key ( & NodeId :: from_pubkey ( & recipient) ) ;
418421
419422 let mut peer_info = peers
423+ . map ( |peer| ( NodeId :: from_pubkey ( & peer. node_id ) , peer) )
420424 // Limit to peers with announced channels
421- . filter_map ( |peer|
425+ . filter_map ( |( node_id , peer) |
422426 network_graph
423- . node ( & NodeId :: from_pubkey ( & peer . node_id ) )
427+ . node ( & node_id)
424428 . filter ( |info| info. channels . len ( ) >= MIN_PEER_CHANNELS )
425- . map ( |info| ( peer, info. is_tor_only ( ) , info. channels . len ( ) ) )
429+ . map ( |info| ( node_id , peer, info. is_tor_only ( ) , & info. channels ) )
426430 )
427431 // Exclude Tor-only nodes when the recipient is announced.
428- . filter ( |( _, is_tor_only, _) | !( * is_tor_only && is_recipient_announced) )
432+ . filter ( |( _, _ , is_tor_only, _) | !( * is_tor_only && is_recipient_announced) )
429433 . collect :: < Vec < _ > > ( ) ;
430434
431435 // Prefer using non-Tor nodes with the most channels as the introduction node.
432- peer_info. sort_unstable_by ( |( _, a_tor_only, a_channels) , ( _, b_tor_only, b_channels) | {
433- a_tor_only. cmp ( b_tor_only) . then ( a_channels. cmp ( b_channels) . reverse ( ) )
436+ peer_info. sort_unstable_by ( |( _, _ , a_tor_only, a_channels) , ( _ , _, b_tor_only, b_channels) | {
437+ a_tor_only. cmp ( b_tor_only) . then ( a_channels. len ( ) . cmp ( & b_channels. len ( ) ) . reverse ( ) )
434438 } ) ;
435439
436- let paths = peer_info. into_iter ( )
437- . map ( |( peer, _, _) | {
438- BlindedPath :: new_for_message ( & [ peer] , recipient, & * self . entropy_source , secp_ctx)
439- } )
440- . take ( MAX_PATHS )
441- . collect :: < Result < Vec < _ > , _ > > ( ) ;
442-
443- let mut paths = match paths {
444- Ok ( paths) if !paths. is_empty ( ) => Ok ( paths) ,
445- _ => {
446- if is_recipient_announced {
447- BlindedPath :: one_hop_for_message ( recipient, & * self . entropy_source , secp_ctx)
448- . map ( |path| vec ! [ path] )
449- } else {
450- Err ( ( ) )
451- }
452- } ,
453- } ?;
440+ let three_hop_paths = peer_info. iter ( )
441+ // Pair peers with their other peers
442+ . flat_map ( |( node_id, peer, _, channels) |
443+ channels
444+ . iter ( )
445+ . filter_map ( |scid| network_graph. channels ( ) . get ( scid) )
446+ . filter_map ( move |info| info
447+ . as_directed_to ( & node_id)
448+ . map ( |( _, source) | source)
449+ )
450+ . filter ( |source| * * source != recipient_node_id)
451+ . filter ( |source| network_graph
452+ . node ( source)
453+ . and_then ( |info| info. announcement_info . as_ref ( ) )
454+ . map ( |info| info. features . supports_onion_messages ( ) )
455+ . unwrap_or ( false )
456+ )
457+ . filter_map ( |source| source. as_pubkey ( ) . ok ( ) )
458+ . map ( move |source_pubkey| ( source_pubkey, peer. clone ( ) ) )
459+ )
460+ . map ( |( source_pubkey, peer) | BlindedPath :: new_for_message ( & [ ForwardNode { node_id : source_pubkey, short_channel_id : None } , peer] , recipient, entropy_source, secp_ctx) )
461+ . take ( MAX_PATHS ) ;
462+
463+ let two_hop_paths = peer_info
464+ . iter ( )
465+ . map ( |( _, peer, _, _) | BlindedPath :: new_for_message ( & [ peer. clone ( ) ] , recipient, entropy_source, secp_ctx) )
466+ . take ( MAX_PATHS ) ;
467+
468+ let mut paths = three_hop_paths
469+ . collect :: < Result < Vec < _ > , _ > > ( ) . ok ( )
470+ . and_then ( |paths| ( !paths. is_empty ( ) ) . then ( || paths) )
471+ . or_else ( || two_hop_paths. collect :: < Result < Vec < _ > , _ > > ( ) . ok ( ) )
472+ . and_then ( |paths| ( !paths. is_empty ( ) ) . then ( || paths) )
473+ . or_else ( || is_recipient_announced
474+ . then ( || BlindedPath :: one_hop_for_message ( recipient, entropy_source, secp_ctx)
475+ . map ( |path| vec ! [ path] )
476+ . unwrap_or ( vec ! [ ] )
477+ )
478+ )
479+ . ok_or ( ( ) ) ?;
480+
481+ if paths. is_empty ( ) {
482+ return Err ( ( ) ) ;
483+ }
454484
455485 if compact_paths {
456486 for path in & mut paths {
0 commit comments