Skip to content

Commit 55221e7

Browse files
committed
Account for fully private paths.
1 parent 19b3d2a commit 55221e7

File tree

1 file changed

+46
-37
lines changed

1 file changed

+46
-37
lines changed

lightning/src/routing/router.rs

Lines changed: 46 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,49 +1521,58 @@ where L::Target: Logger {
15211521
let mut shadow_ctlv_expiry_delta_offset: u32 = 0;
15221522

15231523
// 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+
}
15611558
}
15621559
}
15631560
}
15641561
}
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);
15651570
}
15661571

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+
15671576
// Add 'shadow' CLTV offset to all hops but the final one
15681577
for h in path {
15691578
if let Ok(hop) = h {

0 commit comments

Comments
 (0)