Skip to content

Commit fd46193

Browse files
committed
Expand the Route object to include multiple paths.
Rather big diff, but its all mechanical and doesn't introduce any new features.
1 parent 53b8477 commit fd46193

File tree

7 files changed

+343
-302
lines changed

7 files changed

+343
-302
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -409,14 +409,14 @@ pub fn do_test(data: &[u8]) {
409409
let payment_hash = Sha256::hash(&[payment_id; 1]);
410410
payment_id = payment_id.wrapping_add(1);
411411
if let Err(_) = $source.send_payment(Route {
412-
hops: vec![RouteHop {
412+
paths: vec![vec![RouteHop {
413413
pubkey: $dest.0.get_our_node_id(),
414414
node_features: NodeFeatures::empty(),
415415
short_channel_id: $dest.1,
416416
channel_features: ChannelFeatures::empty(),
417417
fee_msat: 5000000,
418418
cltv_expiry_delta: 200,
419-
}],
419+
}]],
420420
}, PaymentHash(payment_hash.into_inner()), None) {
421421
// Probably ran out of funds
422422
test_return!();
@@ -426,7 +426,7 @@ pub fn do_test(data: &[u8]) {
426426
let payment_hash = Sha256::hash(&[payment_id; 1]);
427427
payment_id = payment_id.wrapping_add(1);
428428
if let Err(_) = $source.send_payment(Route {
429-
hops: vec![RouteHop {
429+
paths: vec![vec![RouteHop {
430430
pubkey: $middle.0.get_our_node_id(),
431431
node_features: NodeFeatures::empty(),
432432
short_channel_id: $middle.1,
@@ -440,7 +440,7 @@ pub fn do_test(data: &[u8]) {
440440
channel_features: ChannelFeatures::empty(),
441441
fee_msat: 5000000,
442442
cltv_expiry_delta: 200,
443-
}],
443+
}]],
444444
}, PaymentHash(payment_hash.into_inner()), None) {
445445
// Probably ran out of funds
446446
test_return!();

lightning/src/ln/channelmanager.rs

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use chain::transaction::OutPoint;
3030
use ln::channel::{Channel, ChannelError};
3131
use ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateErr, ManyChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY};
3232
use ln::features::{InitFeatures, NodeFeatures};
33-
use ln::router::Route;
33+
use ln::router::{Route, RouteHop};
3434
use ln::msgs;
3535
use ln::onion_utils;
3636
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
@@ -132,7 +132,7 @@ struct ClaimableHTLC {
132132
pub(super) enum HTLCSource {
133133
PreviousHopData(HTLCPreviousHopData),
134134
OutboundRoute {
135-
route: Route,
135+
path: Vec<RouteHop>,
136136
session_priv: SecretKey,
137137
/// Technically we can recalculate this from the route, but we cache it here to avoid
138138
/// doing a double-pass on route when we get a failure back
@@ -143,7 +143,7 @@ pub(super) enum HTLCSource {
143143
impl HTLCSource {
144144
pub fn dummy() -> Self {
145145
HTLCSource::OutboundRoute {
146-
route: Route { hops: Vec::new() },
146+
path: Vec::new(),
147147
session_priv: SecretKey::from_slice(&[1; 32]).unwrap(),
148148
first_hop_htlc_msat: 0,
149149
}
@@ -1202,23 +1202,26 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
12021202
/// If a payment_secret *is* provided, we assume that the invoice had the basic_mpp feature bit
12031203
/// set (either as required or as available).
12041204
pub fn send_payment(&self, route: Route, payment_hash: PaymentHash, payment_secret: Option<&[u8; 32]>) -> Result<(), APIError> {
1205-
if route.hops.len() < 1 || route.hops.len() > 20 {
1206-
return Err(APIError::RouteError{err: "Route didn't go anywhere/had bogus size"});
1205+
if route.paths.len() < 1 || route.paths.len() > 1 {
1206+
return Err(APIError::RouteError{err: "We currently don't support MPP, and we need at least one path"});
1207+
}
1208+
if route.paths[0].len() < 1 || route.paths[0].len() > 20 {
1209+
return Err(APIError::RouteError{err: "Path didn't go anywhere/had bogus size"});
12071210
}
12081211
let our_node_id = self.get_our_node_id();
1209-
for (idx, hop) in route.hops.iter().enumerate() {
1210-
if idx != route.hops.len() - 1 && hop.pubkey == our_node_id {
1211-
return Err(APIError::RouteError{err: "Route went through us but wasn't a simple rebalance loop to us"});
1212+
for (idx, hop) in route.paths[0].iter().enumerate() {
1213+
if idx != route.paths[0].len() - 1 && hop.pubkey == our_node_id {
1214+
return Err(APIError::RouteError{err: "Path went through us but wasn't a simple rebalance loop to us"});
12121215
}
12131216
}
12141217

12151218
let (session_priv, prng_seed) = self.keys_manager.get_onion_rand();
12161219

12171220
let cur_height = self.latest_block_height.load(Ordering::Acquire) as u32 + 1;
12181221

1219-
let onion_keys = secp_call!(onion_utils::construct_onion_keys(&self.secp_ctx, &route, &session_priv),
1222+
let onion_keys = secp_call!(onion_utils::construct_onion_keys(&self.secp_ctx, &route.paths[0], &session_priv),
12201223
APIError::RouteError{err: "Pubkey along hop was maliciously selected"});
1221-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route, payment_secret, cur_height)?;
1224+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], payment_secret, cur_height)?;
12221225
if onion_utils::route_size_insane(&onion_payloads) {
12231226
return Err(APIError::RouteError{err: "Route size too large considering onion data"});
12241227
}
@@ -1229,22 +1232,22 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
12291232
let mut channel_lock = self.channel_state.lock().unwrap();
12301233
let err: Result<(), _> = loop {
12311234

1232-
let id = match channel_lock.short_to_id.get(&route.hops.first().unwrap().short_channel_id) {
1235+
let id = match channel_lock.short_to_id.get(&route.paths[0].first().unwrap().short_channel_id) {
12331236
None => return Err(APIError::ChannelUnavailable{err: "No channel available with first hop!"}),
12341237
Some(id) => id.clone(),
12351238
};
12361239

12371240
let channel_state = &mut *channel_lock;
12381241
if let hash_map::Entry::Occupied(mut chan) = channel_state.by_id.entry(id) {
12391242
match {
1240-
if chan.get().get_their_node_id() != route.hops.first().unwrap().pubkey {
1243+
if chan.get().get_their_node_id() != route.paths[0].first().unwrap().pubkey {
12411244
return Err(APIError::RouteError{err: "Node ID mismatch on first hop!"});
12421245
}
12431246
if !chan.get().is_live() {
12441247
return Err(APIError::ChannelUnavailable{err: "Peer for first hop currently disconnected/pending monitor update!"});
12451248
}
12461249
break_chan_entry!(self, chan.get_mut().send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute {
1247-
route: route.clone(),
1250+
path: route.paths[0].clone(),
12481251
session_priv: session_priv.clone(),
12491252
first_hop_htlc_msat: htlc_msat,
12501253
}, onion_packet), channel_state, chan)
@@ -1260,7 +1263,7 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
12601263
}
12611264

12621265
channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
1263-
node_id: route.hops.first().unwrap().pubkey,
1266+
node_id: route.paths[0].first().unwrap().pubkey,
12641267
updates: msgs::CommitmentUpdate {
12651268
update_add_htlcs: vec![update_add],
12661269
update_fulfill_htlcs: Vec::new(),
@@ -1277,7 +1280,7 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
12771280
return Ok(());
12781281
};
12791282

1280-
match handle_error!(self, err, route.hops.first().unwrap().pubkey, channel_lock) {
1283+
match handle_error!(self, err, route.paths[0].first().unwrap().pubkey, channel_lock) {
12811284
Ok(_) => unreachable!(),
12821285
Err(e) => { Err(APIError::ChannelUnavailable { err: e.err }) }
12831286
}
@@ -1730,7 +1733,7 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
17301733
//between the branches here. We should make this async and move it into the forward HTLCs
17311734
//timer handling.
17321735
match source {
1733-
HTLCSource::OutboundRoute { ref route, .. } => {
1736+
HTLCSource::OutboundRoute { ref path, .. } => {
17341737
log_trace!(self, "Failing outbound payment HTLC with payment_hash {}", log_bytes!(payment_hash.0));
17351738
mem::drop(channel_state_lock);
17361739
match &onion_error {
@@ -1772,7 +1775,7 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
17721775
self.pending_events.lock().unwrap().push(
17731776
events::Event::PaymentFailed {
17741777
payment_hash: payment_hash.clone(),
1775-
rejected_by_dest: route.hops.len() == 1,
1778+
rejected_by_dest: path.len() == 1,
17761779
#[cfg(test)]
17771780
error_code: Some(*failure_code),
17781781
}
@@ -1836,9 +1839,19 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
18361839
let mut channel_state = Some(self.channel_state.lock().unwrap());
18371840
let removed_source = channel_state.as_mut().unwrap().claimable_htlcs.remove(&(payment_hash, *payment_secret));
18381841
if let Some(mut sources) = removed_source {
1842+
assert!(!sources.is_empty());
1843+
let passes_value = if let &Some(ref data) = &sources[0].payment_data {
1844+
assert!(payment_secret.is_some());
1845+
if data.total_msat == expected_amount { true } else { false }
1846+
} else {
1847+
assert!(payment_secret.is_none());
1848+
false
1849+
};
1850+
1851+
let mut one_claimed = false;
18391852
for htlc in sources.drain(..) {
18401853
if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); }
1841-
if htlc.value < expected_amount || htlc.value > expected_amount * 2 {
1854+
if !passes_value && (htlc.value < expected_amount || htlc.value > expected_amount * 2) {
18421855
let mut htlc_msat_data = byte_utils::be64_to_array(htlc.value).to_vec();
18431856
let mut height_data = byte_utils::be32_to_array(self.latest_block_height.load(Ordering::Acquire) as u32).to_vec();
18441857
htlc_msat_data.append(&mut height_data);
@@ -1847,9 +1860,10 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
18471860
HTLCFailReason::Reason { failure_code: 0x4000|15, data: htlc_msat_data });
18481861
} else {
18491862
self.claim_funds_internal(channel_state.take().unwrap(), HTLCSource::PreviousHopData(htlc.prev_hop), payment_preimage);
1863+
one_claimed = true;
18501864
}
18511865
}
1852-
true
1866+
one_claimed
18531867
} else { false }
18541868
}
18551869
fn claim_funds_internal(&self, mut channel_state_lock: MutexGuard<ChannelHolder<ChanSigner>>, source: HTLCSource, payment_preimage: PaymentPreimage) {
@@ -3308,9 +3322,9 @@ impl Writeable for HTLCSource {
33083322
0u8.write(writer)?;
33093323
hop_data.write(writer)?;
33103324
},
3311-
&HTLCSource::OutboundRoute { ref route, ref session_priv, ref first_hop_htlc_msat } => {
3325+
&HTLCSource::OutboundRoute { ref path, ref session_priv, ref first_hop_htlc_msat } => {
33123326
1u8.write(writer)?;
3313-
route.write(writer)?;
3327+
path.write(writer)?;
33143328
session_priv.write(writer)?;
33153329
first_hop_htlc_msat.write(writer)?;
33163330
}
@@ -3324,7 +3338,7 @@ impl Readable for HTLCSource {
33243338
match <u8 as Readable>::read(reader)? {
33253339
0 => Ok(HTLCSource::PreviousHopData(Readable::read(reader)?)),
33263340
1 => Ok(HTLCSource::OutboundRoute {
3327-
route: Readable::read(reader)?,
3341+
path: Readable::read(reader)?,
33283342
session_priv: Readable::read(reader)?,
33293343
first_hop_htlc_msat: Readable::read(reader)?,
33303344
}),

lightning/src/ln/functional_test_utils.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -897,8 +897,9 @@ pub const TEST_FINAL_CLTV: u32 = 32;
897897

898898
pub fn route_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], recv_value: u64) -> (PaymentPreimage, PaymentHash) {
899899
let route = origin_node.router.get_route(&expected_route.last().unwrap().node.get_our_node_id(), None, &Vec::new(), recv_value, TEST_FINAL_CLTV).unwrap();
900-
assert_eq!(route.hops.len(), expected_route.len());
901-
for (node, hop) in expected_route.iter().zip(route.hops.iter()) {
900+
assert_eq!(route.paths.len(), 1);
901+
assert_eq!(route.paths[0].len(), expected_route.len());
902+
for (node, hop) in expected_route.iter().zip(route.paths[0].iter()) {
902903
assert_eq!(hop.pubkey, node.node.get_our_node_id());
903904
}
904905

@@ -907,8 +908,9 @@ pub fn route_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route:
907908

908909
pub fn route_over_limit<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], recv_value: u64) {
909910
let route = origin_node.router.get_route(&expected_route.last().unwrap().node.get_our_node_id(), None, &Vec::new(), recv_value, TEST_FINAL_CLTV).unwrap();
910-
assert_eq!(route.hops.len(), expected_route.len());
911-
for (node, hop) in expected_route.iter().zip(route.hops.iter()) {
911+
assert_eq!(route.paths.len(), 1);
912+
assert_eq!(route.paths[0].len(), expected_route.len());
913+
for (node, hop) in expected_route.iter().zip(route.paths[0].iter()) {
912914
assert_eq!(hop.pubkey, node.node.get_our_node_id());
913915
}
914916

0 commit comments

Comments
 (0)