@@ -490,6 +490,9 @@ where
490
490
> (
491
491
& self , recipient : PublicKey , peers : I , secp_ctx : & Secp256k1 < T > , compact_paths : bool
492
492
) -> Result < Vec < BlindedPath > , ( ) > {
493
+ let entropy_source = & * self . entropy_source ;
494
+ let recipient_node_id = NodeId :: from_pubkey ( & recipient) ;
495
+
493
496
// Limit the number of blinded paths that are computed.
494
497
const MAX_PATHS : usize = 3 ;
495
498
@@ -502,40 +505,67 @@ where
502
505
network_graph. nodes ( ) . contains_key ( & NodeId :: from_pubkey ( & recipient) ) ;
503
506
504
507
let mut peer_info = peers
508
+ . map ( |peer| ( NodeId :: from_pubkey ( & peer. node_id ) , peer) )
505
509
// Limit to peers with announced channels
506
- . filter_map ( |peer|
510
+ . filter_map ( |( node_id , peer) |
507
511
network_graph
508
- . node ( & NodeId :: from_pubkey ( & peer . node_id ) )
512
+ . node ( & node_id)
509
513
. filter ( |info| info. channels . len ( ) >= MIN_PEER_CHANNELS )
510
- . map ( |info| ( peer, info. is_tor_only ( ) , info. channels . len ( ) ) )
514
+ . map ( |info| ( node_id , peer, info. is_tor_only ( ) , & info. channels ) )
511
515
)
512
516
// Exclude Tor-only nodes when the recipient is announced.
513
- . filter ( |( _, is_tor_only, _) | !( * is_tor_only && is_recipient_announced) )
517
+ . filter ( |( _, _ , is_tor_only, _) | !( * is_tor_only && is_recipient_announced) )
514
518
. collect :: < Vec < _ > > ( ) ;
515
519
516
520
// Prefer using non-Tor nodes with the most channels as the introduction node.
517
- peer_info. sort_unstable_by ( |( _, a_tor_only, a_channels) , ( _, b_tor_only, b_channels) | {
518
- a_tor_only. cmp ( b_tor_only) . then ( a_channels. cmp ( b_channels) . reverse ( ) )
521
+ peer_info. sort_unstable_by ( |( _, _ , a_tor_only, a_channels) , ( _ , _, b_tor_only, b_channels) | {
522
+ a_tor_only. cmp ( b_tor_only) . then ( a_channels. len ( ) . cmp ( & b_channels. len ( ) ) . reverse ( ) )
519
523
} ) ;
520
524
521
- let paths = peer_info. into_iter ( )
522
- . map ( |( peer, _, _) | {
523
- BlindedPath :: new_for_message ( & [ peer] , recipient, & * self . entropy_source , secp_ctx)
524
- } )
525
- . take ( MAX_PATHS )
526
- . collect :: < Result < Vec < _ > , _ > > ( ) ;
527
-
528
- let mut paths = match paths {
529
- Ok ( paths) if !paths. is_empty ( ) => Ok ( paths) ,
530
- _ => {
531
- if is_recipient_announced {
532
- BlindedPath :: one_hop_for_message ( recipient, & * self . entropy_source , secp_ctx)
533
- . map ( |path| vec ! [ path] )
534
- } else {
535
- Err ( ( ) )
536
- }
537
- } ,
538
- } ?;
525
+ let three_hop_paths = peer_info. iter ( )
526
+ // Pair peers with their other peers
527
+ . flat_map ( |( node_id, peer, _, channels) |
528
+ channels
529
+ . iter ( )
530
+ . filter_map ( |scid| network_graph. channels ( ) . get ( scid) )
531
+ . filter_map ( move |info| info
532
+ . as_directed_to ( & node_id)
533
+ . map ( |( _, source) | source)
534
+ )
535
+ . filter ( |source| * * source != recipient_node_id)
536
+ . filter ( |source| network_graph
537
+ . node ( source)
538
+ . and_then ( |info| info. announcement_info . as_ref ( ) )
539
+ . map ( |info| info. features ( ) . supports_onion_messages ( ) )
540
+ . unwrap_or ( false )
541
+ )
542
+ . filter_map ( |source| source. as_pubkey ( ) . ok ( ) )
543
+ . map ( move |source_pubkey| ( source_pubkey, peer. clone ( ) ) )
544
+ )
545
+ . map ( |( source_pubkey, peer) | BlindedPath :: new_for_message ( & [ ForwardNode { node_id : source_pubkey, short_channel_id : None } , peer] , recipient, entropy_source, secp_ctx) )
546
+ . take ( MAX_PATHS ) ;
547
+
548
+ let two_hop_paths = peer_info
549
+ . iter ( )
550
+ . map ( |( _, peer, _, _) | BlindedPath :: new_for_message ( & [ peer. clone ( ) ] , recipient, entropy_source, secp_ctx) )
551
+ . take ( MAX_PATHS ) ;
552
+
553
+ let mut paths = three_hop_paths
554
+ . collect :: < Result < Vec < _ > , _ > > ( ) . ok ( )
555
+ . and_then ( |paths| ( !paths. is_empty ( ) ) . then ( || paths) )
556
+ . or_else ( || two_hop_paths. collect :: < Result < Vec < _ > , _ > > ( ) . ok ( ) )
557
+ . and_then ( |paths| ( !paths. is_empty ( ) ) . then ( || paths) )
558
+ . or_else ( || is_recipient_announced
559
+ . then ( || BlindedPath :: one_hop_for_message ( recipient, entropy_source, secp_ctx)
560
+ . map ( |path| vec ! [ path] )
561
+ . unwrap_or ( vec ! [ ] )
562
+ )
563
+ )
564
+ . ok_or ( ( ) ) ?;
565
+
566
+ if paths. is_empty ( ) {
567
+ return Err ( ( ) ) ;
568
+ }
539
569
540
570
if compact_paths {
541
571
for path in & mut paths {
0 commit comments