Skip to content

Commit d6877fa

Browse files
TheBlueMattvalentinewallace
authored andcommitted
Ignore partially-pruned channels during routing
If we prune one side of a channel's `ChannelUpdateInfo` that means the node hasn't been online for two weeks (as they haven't generated a new `channel_update` in that time). In such cases, even if we haven't yet pruned the channel entirely, we should definitely not be treating these channels as candidates for routing. Note that this requires some additional `channel_update`s in the router tests, but all of the new ones are added as disabled channels. Fixes lightningdevkit#1824
1 parent 37bf61c commit d6877fa

File tree

2 files changed

+126
-74
lines changed

2 files changed

+126
-74
lines changed

lightning/src/routing/gossip.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,7 @@ impl ChannelInfo {
879879
/// Returns a [`DirectedChannelInfo`] for the channel directed to the given `target` from a
880880
/// returned `source`, or `None` if `target` is not one of the channel's counterparties.
881881
pub fn as_directed_to(&self, target: &NodeId) -> Option<(DirectedChannelInfo, &NodeId)> {
882+
if self.one_to_two.is_none() || self.two_to_one.is_none() { return None; }
882883
let (direction, source, outbound) = {
883884
if target == &self.node_one {
884885
(self.two_to_one.as_ref(), &self.node_two, false)
@@ -888,12 +889,14 @@ impl ChannelInfo {
888889
return None;
889890
}
890891
};
891-
direction.map(|dir| (DirectedChannelInfo::new(self, dir, outbound), source))
892+
let dir = direction.expect("We checked that both directions are available at the start");
893+
Some((DirectedChannelInfo::new(self, dir, outbound), source))
892894
}
893895

894896
/// Returns a [`DirectedChannelInfo`] for the channel directed from the given `source` to a
895897
/// returned `target`, or `None` if `source` is not one of the channel's counterparties.
896898
pub fn as_directed_from(&self, source: &NodeId) -> Option<(DirectedChannelInfo, &NodeId)> {
899+
if self.one_to_two.is_none() || self.two_to_one.is_none() { return None; }
897900
let (direction, target, outbound) = {
898901
if source == &self.node_one {
899902
(self.one_to_two.as_ref(), &self.node_two, true)
@@ -903,7 +906,8 @@ impl ChannelInfo {
903906
return None;
904907
}
905908
};
906-
direction.map(|dir| (DirectedChannelInfo::new(self, dir, outbound), target))
909+
let dir = direction.expect("We checked that both directions are available at the start");
910+
Some((DirectedChannelInfo::new(self, dir, outbound), target))
907911
}
908912

909913
/// Returns a [`ChannelUpdateInfo`] based on the direction implied by the channel_flag.

lightning/src/routing/router.rs

Lines changed: 120 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -5503,6 +5503,18 @@ mod tests {
55035503
fee_proportional_millionths: 0,
55045504
excess_data: Vec::new()
55055505
});
5506+
update_channel(&gossip_sync, &secp_ctx, &privkeys[3], UnsignedChannelUpdate {
5507+
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
5508+
short_channel_id: 5,
5509+
timestamp: 2,
5510+
flags: 3, // disable direction 1
5511+
cltv_expiry_delta: 0,
5512+
htlc_minimum_msat: 0,
5513+
htlc_maximum_msat: 200_000,
5514+
fee_base_msat: 0,
5515+
fee_proportional_millionths: 0,
5516+
excess_data: Vec::new()
5517+
});
55065518

55075519
// Path via {node7, node2, node4} is channels {12, 13, 6, 11}.
55085520
// Add 100 sats to the capacities of {12, 13}, because these channels
@@ -5680,6 +5692,18 @@ mod tests {
56805692
fee_proportional_millionths: 0,
56815693
excess_data: Vec::new()
56825694
});
5695+
update_channel(&gossip_sync, &secp_ctx, &privkeys[3], UnsignedChannelUpdate {
5696+
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
5697+
short_channel_id: 5,
5698+
timestamp: 2,
5699+
flags: 3, // disable direction 1
5700+
cltv_expiry_delta: 0,
5701+
htlc_minimum_msat: 0,
5702+
htlc_maximum_msat: 200_000,
5703+
fee_base_msat: 0,
5704+
fee_proportional_millionths: 0,
5705+
excess_data: Vec::new()
5706+
});
56835707

56845708
// Path via {node7, node2, node4} is channels {12, 13, 6, 11}.
56855709
// Add 100 sats to the capacities of {12, 13}, because these channels
@@ -5853,6 +5877,18 @@ mod tests {
58535877
fee_proportional_millionths: 0,
58545878
excess_data: Vec::new()
58555879
});
5880+
update_channel(&gossip_sync, &secp_ctx, &privkeys[3], UnsignedChannelUpdate {
5881+
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
5882+
short_channel_id: 5,
5883+
timestamp: 2,
5884+
flags: 3, // Disable direction 1
5885+
cltv_expiry_delta: 0,
5886+
htlc_minimum_msat: 0,
5887+
htlc_maximum_msat: 100_000,
5888+
fee_base_msat: 0,
5889+
fee_proportional_millionths: 0,
5890+
excess_data: Vec::new()
5891+
});
58565892

58575893
// Path via {node7, node2, node4} is channels {12, 13, 6, 11}.
58585894
// All channels should be 100 sats capacity. But for the fee experiment,
@@ -6245,92 +6281,104 @@ mod tests {
62456281
let payment_params = PaymentParameters::from_node_id(nodes[6], 42);
62466282

62476283
add_channel(&gossip_sync, &secp_ctx, &our_privkey, &privkeys[1], ChannelFeatures::from_le_bytes(id_to_feature_flags(6)), 6);
6248-
update_channel(&gossip_sync, &secp_ctx, &our_privkey, UnsignedChannelUpdate {
6249-
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
6250-
short_channel_id: 6,
6251-
timestamp: 1,
6252-
flags: 0,
6253-
cltv_expiry_delta: (6 << 4) | 0,
6254-
htlc_minimum_msat: 0,
6255-
htlc_maximum_msat: MAX_VALUE_MSAT,
6256-
fee_base_msat: 0,
6257-
fee_proportional_millionths: 0,
6258-
excess_data: Vec::new()
6259-
});
6284+
for (key, flags) in [(&our_privkey, 0), (&privkeys[1], 3)] {
6285+
update_channel(&gossip_sync, &secp_ctx, key, UnsignedChannelUpdate {
6286+
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
6287+
short_channel_id: 6,
6288+
timestamp: 1,
6289+
flags,
6290+
cltv_expiry_delta: (6 << 4) | 0,
6291+
htlc_minimum_msat: 0,
6292+
htlc_maximum_msat: MAX_VALUE_MSAT,
6293+
fee_base_msat: 0,
6294+
fee_proportional_millionths: 0,
6295+
excess_data: Vec::new()
6296+
});
6297+
}
62606298
add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[1], NodeFeatures::from_le_bytes(id_to_feature_flags(1)), 0);
62616299

62626300
add_channel(&gossip_sync, &secp_ctx, &privkeys[1], &privkeys[4], ChannelFeatures::from_le_bytes(id_to_feature_flags(5)), 5);
6263-
update_channel(&gossip_sync, &secp_ctx, &privkeys[1], UnsignedChannelUpdate {
6264-
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
6265-
short_channel_id: 5,
6266-
timestamp: 1,
6267-
flags: 0,
6268-
cltv_expiry_delta: (5 << 4) | 0,
6269-
htlc_minimum_msat: 0,
6270-
htlc_maximum_msat: MAX_VALUE_MSAT,
6271-
fee_base_msat: 100,
6272-
fee_proportional_millionths: 0,
6273-
excess_data: Vec::new()
6274-
});
6301+
for (key, flags) in [(&privkeys[1], 0), (&privkeys[4], 3)] {
6302+
update_channel(&gossip_sync, &secp_ctx, key, UnsignedChannelUpdate {
6303+
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
6304+
short_channel_id: 5,
6305+
timestamp: 1,
6306+
flags,
6307+
cltv_expiry_delta: (5 << 4) | 0,
6308+
htlc_minimum_msat: 0,
6309+
htlc_maximum_msat: MAX_VALUE_MSAT,
6310+
fee_base_msat: 100,
6311+
fee_proportional_millionths: 0,
6312+
excess_data: Vec::new()
6313+
});
6314+
}
62756315
add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[4], NodeFeatures::from_le_bytes(id_to_feature_flags(4)), 0);
62766316

62776317
add_channel(&gossip_sync, &secp_ctx, &privkeys[4], &privkeys[3], ChannelFeatures::from_le_bytes(id_to_feature_flags(4)), 4);
6278-
update_channel(&gossip_sync, &secp_ctx, &privkeys[4], UnsignedChannelUpdate {
6279-
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
6280-
short_channel_id: 4,
6281-
timestamp: 1,
6282-
flags: 0,
6283-
cltv_expiry_delta: (4 << 4) | 0,
6284-
htlc_minimum_msat: 0,
6285-
htlc_maximum_msat: MAX_VALUE_MSAT,
6286-
fee_base_msat: 0,
6287-
fee_proportional_millionths: 0,
6288-
excess_data: Vec::new()
6289-
});
6318+
for (key, flags) in [(&privkeys[4], 0), (&privkeys[3], 3)] {
6319+
update_channel(&gossip_sync, &secp_ctx, key, UnsignedChannelUpdate {
6320+
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
6321+
short_channel_id: 4,
6322+
timestamp: 1,
6323+
flags,
6324+
cltv_expiry_delta: (4 << 4) | 0,
6325+
htlc_minimum_msat: 0,
6326+
htlc_maximum_msat: MAX_VALUE_MSAT,
6327+
fee_base_msat: 0,
6328+
fee_proportional_millionths: 0,
6329+
excess_data: Vec::new()
6330+
});
6331+
}
62906332
add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[3], NodeFeatures::from_le_bytes(id_to_feature_flags(3)), 0);
62916333

62926334
add_channel(&gossip_sync, &secp_ctx, &privkeys[3], &privkeys[2], ChannelFeatures::from_le_bytes(id_to_feature_flags(3)), 3);
6293-
update_channel(&gossip_sync, &secp_ctx, &privkeys[3], UnsignedChannelUpdate {
6294-
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
6295-
short_channel_id: 3,
6296-
timestamp: 1,
6297-
flags: 0,
6298-
cltv_expiry_delta: (3 << 4) | 0,
6299-
htlc_minimum_msat: 0,
6300-
htlc_maximum_msat: MAX_VALUE_MSAT,
6301-
fee_base_msat: 0,
6302-
fee_proportional_millionths: 0,
6303-
excess_data: Vec::new()
6304-
});
6335+
for (key, flags) in [(&privkeys[3], 0), (&privkeys[2], 3)] {
6336+
update_channel(&gossip_sync, &secp_ctx, key, UnsignedChannelUpdate {
6337+
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
6338+
short_channel_id: 3,
6339+
timestamp: 1,
6340+
flags,
6341+
cltv_expiry_delta: (3 << 4) | 0,
6342+
htlc_minimum_msat: 0,
6343+
htlc_maximum_msat: MAX_VALUE_MSAT,
6344+
fee_base_msat: 0,
6345+
fee_proportional_millionths: 0,
6346+
excess_data: Vec::new()
6347+
});
6348+
}
63056349
add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[2], NodeFeatures::from_le_bytes(id_to_feature_flags(2)), 0);
63066350

63076351
add_channel(&gossip_sync, &secp_ctx, &privkeys[2], &privkeys[4], ChannelFeatures::from_le_bytes(id_to_feature_flags(2)), 2);
6308-
update_channel(&gossip_sync, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
6309-
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
6310-
short_channel_id: 2,
6311-
timestamp: 1,
6312-
flags: 0,
6313-
cltv_expiry_delta: (2 << 4) | 0,
6314-
htlc_minimum_msat: 0,
6315-
htlc_maximum_msat: MAX_VALUE_MSAT,
6316-
fee_base_msat: 0,
6317-
fee_proportional_millionths: 0,
6318-
excess_data: Vec::new()
6319-
});
6352+
for (key, flags) in [(&privkeys[2], 0), (&privkeys[4], 3)] {
6353+
update_channel(&gossip_sync, &secp_ctx, key, UnsignedChannelUpdate {
6354+
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
6355+
short_channel_id: 2,
6356+
timestamp: 1,
6357+
flags,
6358+
cltv_expiry_delta: (2 << 4) | 0,
6359+
htlc_minimum_msat: 0,
6360+
htlc_maximum_msat: MAX_VALUE_MSAT,
6361+
fee_base_msat: 0,
6362+
fee_proportional_millionths: 0,
6363+
excess_data: Vec::new()
6364+
});
6365+
}
63206366

63216367
add_channel(&gossip_sync, &secp_ctx, &privkeys[4], &privkeys[6], ChannelFeatures::from_le_bytes(id_to_feature_flags(1)), 1);
6322-
update_channel(&gossip_sync, &secp_ctx, &privkeys[4], UnsignedChannelUpdate {
6323-
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
6324-
short_channel_id: 1,
6325-
timestamp: 1,
6326-
flags: 0,
6327-
cltv_expiry_delta: (1 << 4) | 0,
6328-
htlc_minimum_msat: 100,
6329-
htlc_maximum_msat: MAX_VALUE_MSAT,
6330-
fee_base_msat: 0,
6331-
fee_proportional_millionths: 0,
6332-
excess_data: Vec::new()
6333-
});
6368+
for (key, flags) in [(&privkeys[4], 0), (&privkeys[6], 3)] {
6369+
update_channel(&gossip_sync, &secp_ctx, key, UnsignedChannelUpdate {
6370+
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
6371+
short_channel_id: 1,
6372+
timestamp: 1,
6373+
flags,
6374+
cltv_expiry_delta: (1 << 4) | 0,
6375+
htlc_minimum_msat: 100,
6376+
htlc_maximum_msat: MAX_VALUE_MSAT,
6377+
fee_base_msat: 0,
6378+
fee_proportional_millionths: 0,
6379+
excess_data: Vec::new()
6380+
});
6381+
}
63346382
add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[6], NodeFeatures::from_le_bytes(id_to_feature_flags(6)), 0);
63356383

63366384
{

0 commit comments

Comments
 (0)