@@ -1521,49 +1521,58 @@ where L::Target: Logger {
1521
1521
let mut shadow_ctlv_expiry_delta_offset: u32 = 0 ;
1522
1522
1523
1523
// Choose the last publicly known node as the starting point for the random walk
1524
- let mut cur_node_iter = path. iter ( ) . rev ( ) ;
1525
- let mut cur_node_id = NodeId :: from_pubkey ( & cur_node_iter. next ( ) . unwrap ( ) . as_ref ( ) . unwrap ( ) . pubkey ) ;
1526
- assert_eq ! ( cur_node_id, payee_node_id) ;
1527
- while !network_nodes. contains_key ( & cur_node_id) {
1528
- cur_node_id = NodeId :: from_pubkey ( & cur_node_iter. next ( ) . unwrap ( ) . as_ref ( ) . unwrap ( ) . pubkey ) ;
1529
- }
1530
-
1531
- // Init PRNG
1532
- let mut path_nonce = [ 0u8 ; 8 ] ;
1533
- path_nonce. copy_from_slice ( & cur_node_id. as_slice ( ) [ ..8 ] ) ;
1534
- let mut prng = ChaCha20 :: new ( random_seed_bytes, & path_nonce) ;
1535
- let mut random_path_bytes = [ 0u8 ; 8 ] ;
1536
-
1537
- // Pick a random path length in [1 .. 3]
1538
- prng. process_in_place ( & mut random_path_bytes) ;
1539
- let random_walk_length = usize:: from_be_bytes ( random_path_bytes) . wrapping_rem ( 3 ) . wrapping_add ( 1 ) ;
1540
-
1541
- for _random_hop in 0 ..random_walk_length {
1542
- if let Some ( cur_node) = network_nodes. get ( & cur_node_id) {
1543
- // Randomly choose the next hop
1544
- prng. process_in_place ( & mut random_path_bytes) ;
1545
- if let Some ( random_index) = usize:: from_be_bytes ( random_path_bytes) . checked_rem ( cur_node. channels . len ( ) ) {
1546
- if let Some ( random_channel_id) = cur_node. channels . get ( random_index) {
1547
- if let Some ( random_channel) = network_channels. get ( random_channel_id) {
1548
- if random_channel. node_one == cur_node_id {
1549
- cur_node_id = random_channel. node_two ;
1550
- if let Some ( dir_info) = & random_channel. one_to_two {
1551
- shadow_ctlv_expiry_delta_offset = shadow_ctlv_expiry_delta_offset
1552
- . checked_add ( dir_info. cltv_expiry_delta . into ( ) ) . unwrap_or ( shadow_ctlv_expiry_delta_offset) ;
1553
- }
1554
- } else {
1555
- cur_node_id = random_channel. node_one ;
1556
- if let Some ( dir_info) = & random_channel. two_to_one {
1557
- shadow_ctlv_expiry_delta_offset = shadow_ctlv_expiry_delta_offset
1558
- . checked_add ( dir_info. cltv_expiry_delta . into ( ) ) . unwrap_or ( shadow_ctlv_expiry_delta_offset) ;
1559
- }
1560
- } ;
1524
+ if let Some ( starting_hop) = path. iter ( ) . rev ( ) . find ( |h| network_nodes. contains_key ( & NodeId :: from_pubkey ( & h. as_ref ( ) . unwrap ( ) . pubkey ) ) ) {
1525
+ let mut cur_node_id = NodeId :: from_pubkey ( & starting_hop. as_ref ( ) . unwrap ( ) . pubkey ) ;
1526
+
1527
+ // Init PRNG with path nonce
1528
+ let mut path_nonce = [ 0u8 ; 8 ] ;
1529
+ path_nonce. copy_from_slice ( & cur_node_id. as_slice ( ) [ ..8 ] ) ;
1530
+ let mut prng = ChaCha20 :: new ( random_seed_bytes, & path_nonce) ;
1531
+ let mut random_path_bytes = [ 0u8 ; 8 ] ;
1532
+
1533
+ // Pick a random path length in [1 .. 3]
1534
+ prng. process_in_place ( & mut random_path_bytes) ;
1535
+ let random_walk_length = usize:: from_be_bytes ( random_path_bytes) . wrapping_rem ( 3 ) . wrapping_add ( 1 ) ;
1536
+
1537
+ for _random_hop in 0 ..random_walk_length {
1538
+ if let Some ( cur_node) = network_nodes. get ( & cur_node_id) {
1539
+ // Randomly choose the next hop
1540
+ prng. process_in_place ( & mut random_path_bytes) ;
1541
+ if let Some ( random_index) = usize:: from_be_bytes ( random_path_bytes) . checked_rem ( cur_node. channels . len ( ) ) {
1542
+ if let Some ( random_channel_id) = cur_node. channels . get ( random_index) {
1543
+ if let Some ( random_channel) = network_channels. get ( random_channel_id) {
1544
+ if random_channel. node_one == cur_node_id {
1545
+ cur_node_id = random_channel. node_two ;
1546
+ if let Some ( dir_info) = & random_channel. one_to_two {
1547
+ shadow_ctlv_expiry_delta_offset = shadow_ctlv_expiry_delta_offset
1548
+ . checked_add ( dir_info. cltv_expiry_delta . into ( ) ) . unwrap_or ( shadow_ctlv_expiry_delta_offset) ;
1549
+ }
1550
+ } else {
1551
+ cur_node_id = random_channel. node_one ;
1552
+ if let Some ( dir_info) = & random_channel. two_to_one {
1553
+ shadow_ctlv_expiry_delta_offset = shadow_ctlv_expiry_delta_offset
1554
+ . checked_add ( dir_info. cltv_expiry_delta . into ( ) ) . unwrap_or ( shadow_ctlv_expiry_delta_offset) ;
1555
+ }
1556
+ } ;
1557
+ }
1561
1558
}
1562
1559
}
1563
1560
}
1564
1561
}
1562
+ } else {
1563
+ // If the entire path is private, choose a random offset from multiples of 144, i.e., our
1564
+ // default cltv_expiry_delta
1565
+ let mut prng = ChaCha20 :: new ( random_seed_bytes, & [ 0u8 ; 8 ] ) ;
1566
+ let mut random_bytes = [ 0u8 ; 4 ] ;
1567
+ prng. process_in_place ( & mut random_bytes) ;
1568
+ let random_walk_length = u32:: from_be_bytes ( random_bytes) . wrapping_rem ( 3 ) . wrapping_add ( 1 ) ;
1569
+ shadow_ctlv_expiry_delta_offset = random_walk_length. wrapping_mul ( 144 ) ;
1565
1570
}
1566
1571
1572
+ // Limit the offset to reduce the payment failure probabilty
1573
+ const MAX_SHADOW_CLTV_EXPIRY_DELTA_OFFSET : u32 = 432 ; // 3*144
1574
+ shadow_ctlv_expiry_delta_offset = cmp:: min ( shadow_ctlv_expiry_delta_offset, MAX_SHADOW_CLTV_EXPIRY_DELTA_OFFSET ) ;
1575
+
1567
1576
// Add 'shadow' CLTV offset to all hops but the final one
1568
1577
for h in path {
1569
1578
if let Ok ( hop) = h {
0 commit comments