Skip to content

Commit ae0ad73

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 822f45e commit ae0ad73

File tree

7 files changed

+342
-301
lines changed

7 files changed

+342
-301
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -411,14 +411,14 @@ pub fn do_test(data: &[u8]) {
411411
let payment_hash = Sha256::hash(&[payment_id; 1]);
412412
payment_id = payment_id.wrapping_add(1);
413413
if let Err(_) = $source.send_payment(Route {
414-
hops: vec![RouteHop {
414+
paths: vec![vec![RouteHop {
415415
pubkey: $dest.0.get_our_node_id(),
416416
node_features: NodeFeatures::empty(),
417417
short_channel_id: $dest.1,
418418
channel_features: ChannelFeatures::empty(),
419419
fee_msat: 5000000,
420420
cltv_expiry_delta: 200,
421-
}],
421+
}]],
422422
}, PaymentHash(payment_hash.into_inner()), None) {
423423
// Probably ran out of funds
424424
test_return!();
@@ -428,7 +428,7 @@ pub fn do_test(data: &[u8]) {
428428
let payment_hash = Sha256::hash(&[payment_id; 1]);
429429
payment_id = payment_id.wrapping_add(1);
430430
if let Err(_) = $source.send_payment(Route {
431-
hops: vec![RouteHop {
431+
paths: vec![vec![RouteHop {
432432
pubkey: $middle.0.get_our_node_id(),
433433
node_features: NodeFeatures::empty(),
434434
short_channel_id: $middle.1,
@@ -442,7 +442,7 @@ pub fn do_test(data: &[u8]) {
442442
channel_features: ChannelFeatures::empty(),
443443
fee_msat: 5000000,
444444
cltv_expiry_delta: 200,
445-
}],
445+
}]],
446446
}, PaymentHash(payment_hash.into_inner()), None) {
447447
// Probably ran out of funds
448448
test_return!();

lightning/src/ln/channelmanager.rs

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ use chain::chaininterface::{BroadcasterInterface,ChainListener,FeeEstimator};
2929
use chain::transaction::OutPoint;
3030
use ln::channel::{Channel, ChannelError};
3131
use ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, ManyChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY};
32-
use ln::router::Route;
3332
use ln::features::{InitFeatures, NodeFeatures};
33+
use ln::router::{Route, RouteHop};
3434
use ln::msgs;
3535
use ln::onion_utils;
3636
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
@@ -130,7 +130,7 @@ struct ClaimableHTLC {
130130
pub(super) enum HTLCSource {
131131
PreviousHopData(HTLCPreviousHopData),
132132
OutboundRoute {
133-
route: Route,
133+
path: Vec<RouteHop>,
134134
session_priv: SecretKey,
135135
/// Technically we can recalculate this from the route, but we cache it here to avoid
136136
/// doing a double-pass on route when we get a failure back
@@ -141,7 +141,7 @@ pub(super) enum HTLCSource {
141141
impl HTLCSource {
142142
pub fn dummy() -> Self {
143143
HTLCSource::OutboundRoute {
144-
route: Route { hops: Vec::new() },
144+
path: Vec::new(),
145145
session_priv: SecretKey::from_slice(&[1; 32]).unwrap(),
146146
first_hop_htlc_msat: 0,
147147
}
@@ -1206,23 +1206,26 @@ impl<ChanSigner: ChannelKeys> ChannelManager<ChanSigner> {
12061206
/// If a payment_secret *is* provided, we assume that the invoice had the basic_mpp feature bit
12071207
/// set (either as required or as available).
12081208
pub fn send_payment(&self, route: Route, payment_hash: PaymentHash, payment_secret: Option<&[u8; 32]>) -> Result<(), APIError> {
1209-
if route.hops.len() < 1 || route.hops.len() > 20 {
1210-
return Err(APIError::RouteError{err: "Route didn't go anywhere/had bogus size"});
1209+
if route.paths.len() < 1 || route.paths.len() > 1 {
1210+
return Err(APIError::RouteError{err: "We currently don't support MPP, and we need at least one path"});
1211+
}
1212+
if route.paths[0].len() < 1 || route.paths[0].len() > 20 {
1213+
return Err(APIError::RouteError{err: "Path didn't go anywhere/had bogus size"});
12111214
}
12121215
let our_node_id = self.get_our_node_id();
1213-
for (idx, hop) in route.hops.iter().enumerate() {
1214-
if idx != route.hops.len() - 1 && hop.pubkey == our_node_id {
1215-
return Err(APIError::RouteError{err: "Route went through us but wasn't a simple rebalance loop to us"});
1216+
for (idx, hop) in route.paths[0].iter().enumerate() {
1217+
if idx != route.paths[0].len() - 1 && hop.pubkey == our_node_id {
1218+
return Err(APIError::RouteError{err: "Path went through us but wasn't a simple rebalance loop to us"});
12161219
}
12171220
}
12181221

12191222
let (session_priv, prng_seed) = self.keys_manager.get_onion_rand();
12201223

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

1223-
let onion_keys = secp_call!(onion_utils::construct_onion_keys(&self.secp_ctx, &route, &session_priv),
1226+
let onion_keys = secp_call!(onion_utils::construct_onion_keys(&self.secp_ctx, &route.paths[0], &session_priv),
12241227
APIError::RouteError{err: "Pubkey along hop was maliciously selected"});
1225-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route, payment_secret, cur_height)?;
1228+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], payment_secret, cur_height)?;
12261229
if onion_utils::route_size_insane(&onion_payloads) {
12271230
return Err(APIError::RouteError{err: "Route had too large size once"});
12281231
}
@@ -1233,22 +1236,22 @@ impl<ChanSigner: ChannelKeys> ChannelManager<ChanSigner> {
12331236
let mut channel_lock = self.channel_state.lock().unwrap();
12341237
let err: Result<(), _> = loop {
12351238

1236-
let id = match channel_lock.short_to_id.get(&route.hops.first().unwrap().short_channel_id) {
1239+
let id = match channel_lock.short_to_id.get(&route.paths[0].first().unwrap().short_channel_id) {
12371240
None => return Err(APIError::ChannelUnavailable{err: "No channel available with first hop!"}),
12381241
Some(id) => id.clone(),
12391242
};
12401243

12411244
let channel_state = channel_lock.borrow_parts();
12421245
if let hash_map::Entry::Occupied(mut chan) = channel_state.by_id.entry(id) {
12431246
match {
1244-
if chan.get().get_their_node_id() != route.hops.first().unwrap().pubkey {
1247+
if chan.get().get_their_node_id() != route.paths[0].first().unwrap().pubkey {
12451248
return Err(APIError::RouteError{err: "Node ID mismatch on first hop!"});
12461249
}
12471250
if !chan.get().is_live() {
12481251
return Err(APIError::ChannelUnavailable{err: "Peer for first hop currently disconnected/pending monitor update!"});
12491252
}
12501253
break_chan_entry!(self, chan.get_mut().send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute {
1251-
route: route.clone(),
1254+
path: route.paths[0].clone(),
12521255
session_priv: session_priv.clone(),
12531256
first_hop_htlc_msat: htlc_msat,
12541257
}, onion_packet), channel_state, chan)
@@ -1264,7 +1267,7 @@ impl<ChanSigner: ChannelKeys> ChannelManager<ChanSigner> {
12641267
}
12651268

12661269
channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
1267-
node_id: route.hops.first().unwrap().pubkey,
1270+
node_id: route.paths[0].first().unwrap().pubkey,
12681271
updates: msgs::CommitmentUpdate {
12691272
update_add_htlcs: vec![update_add],
12701273
update_fulfill_htlcs: Vec::new(),
@@ -1281,7 +1284,7 @@ impl<ChanSigner: ChannelKeys> ChannelManager<ChanSigner> {
12811284
return Ok(());
12821285
};
12831286

1284-
match handle_error!(self, err, route.hops.first().unwrap().pubkey, channel_lock) {
1287+
match handle_error!(self, err, route.paths[0].first().unwrap().pubkey, channel_lock) {
12851288
Ok(_) => unreachable!(),
12861289
Err(e) => { Err(APIError::ChannelUnavailable { err: e.err }) }
12871290
}
@@ -1711,7 +1714,7 @@ impl<ChanSigner: ChannelKeys> ChannelManager<ChanSigner> {
17111714
//between the branches here. We should make this async and move it into the forward HTLCs
17121715
//timer handling.
17131716
match source {
1714-
HTLCSource::OutboundRoute { ref route, .. } => {
1717+
HTLCSource::OutboundRoute { ref path, .. } => {
17151718
log_trace!(self, "Failing outbound payment HTLC with payment_hash {}", log_bytes!(payment_hash.0));
17161719
mem::drop(channel_state_lock);
17171720
match &onion_error {
@@ -1753,7 +1756,7 @@ impl<ChanSigner: ChannelKeys> ChannelManager<ChanSigner> {
17531756
self.pending_events.lock().unwrap().push(
17541757
events::Event::PaymentFailed {
17551758
payment_hash: payment_hash.clone(),
1756-
rejected_by_dest: route.hops.len() == 1,
1759+
rejected_by_dest: path.len() == 1,
17571760
#[cfg(test)]
17581761
error_code: Some(*failure_code),
17591762
}
@@ -1817,9 +1820,19 @@ impl<ChanSigner: ChannelKeys> ChannelManager<ChanSigner> {
18171820
let mut channel_state = Some(self.channel_state.lock().unwrap());
18181821
let removed_source = channel_state.as_mut().unwrap().claimable_htlcs.remove(&(payment_hash, *payment_secret));
18191822
if let Some(mut sources) = removed_source {
1823+
assert!(!sources.is_empty());
1824+
let passes_value = if let &Some(ref data) = &sources[0].payment_data {
1825+
assert!(payment_secret.is_some());
1826+
if data.total_msat == expected_amount { true } else { false }
1827+
} else {
1828+
assert!(payment_secret.is_none());
1829+
false
1830+
};
1831+
1832+
let mut one_claimed = false;
18201833
for htlc in sources.drain(..) {
18211834
if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); }
1822-
if htlc.value < expected_amount || htlc.value > expected_amount * 2 {
1835+
if !passes_value && (htlc.value < expected_amount || htlc.value > expected_amount * 2) {
18231836
let mut htlc_msat_data = byte_utils::be64_to_array(htlc.value).to_vec();
18241837
let mut height_data = byte_utils::be32_to_array(self.latest_block_height.load(Ordering::Acquire) as u32).to_vec();
18251838
htlc_msat_data.append(&mut height_data);
@@ -1828,9 +1841,10 @@ impl<ChanSigner: ChannelKeys> ChannelManager<ChanSigner> {
18281841
HTLCFailReason::Reason { failure_code: 0x4000|15, data: htlc_msat_data });
18291842
} else {
18301843
self.claim_funds_internal(channel_state.take().unwrap(), HTLCSource::PreviousHopData(htlc.src), payment_preimage);
1844+
one_claimed = true;
18311845
}
18321846
}
1833-
true
1847+
one_claimed
18341848
} else { false }
18351849
}
18361850
fn claim_funds_internal(&self, mut channel_state_lock: MutexGuard<ChannelHolder<ChanSigner>>, source: HTLCSource, payment_preimage: PaymentPreimage) {
@@ -3236,9 +3250,9 @@ impl Writeable for HTLCSource {
32363250
0u8.write(writer)?;
32373251
hop_data.write(writer)?;
32383252
},
3239-
&HTLCSource::OutboundRoute { ref route, ref session_priv, ref first_hop_htlc_msat } => {
3253+
&HTLCSource::OutboundRoute { ref path, ref session_priv, ref first_hop_htlc_msat } => {
32403254
1u8.write(writer)?;
3241-
route.write(writer)?;
3255+
path.write(writer)?;
32423256
session_priv.write(writer)?;
32433257
first_hop_htlc_msat.write(writer)?;
32443258
}
@@ -3252,7 +3266,7 @@ impl<R: ::std::io::Read> Readable<R> for HTLCSource {
32523266
match <u8 as Readable<R>>::read(reader)? {
32533267
0 => Ok(HTLCSource::PreviousHopData(Readable::read(reader)?)),
32543268
1 => Ok(HTLCSource::OutboundRoute {
3255-
route: Readable::read(reader)?,
3269+
path: Readable::read(reader)?,
32563270
session_priv: Readable::read(reader)?,
32573271
first_hop_htlc_msat: Readable::read(reader)?,
32583272
}),

lightning/src/ln/functional_test_utils.rs

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

769769
pub fn route_payment(origin_node: &Node, expected_route: &[&Node], recv_value: u64) -> (PaymentPreimage, PaymentHash) {
770770
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();
771-
assert_eq!(route.hops.len(), expected_route.len());
772-
for (node, hop) in expected_route.iter().zip(route.hops.iter()) {
771+
assert_eq!(route.paths.len(), 1);
772+
assert_eq!(route.paths[0].len(), expected_route.len());
773+
for (node, hop) in expected_route.iter().zip(route.paths[0].iter()) {
773774
assert_eq!(hop.pubkey, node.node.get_our_node_id());
774775
}
775776

@@ -778,8 +779,9 @@ pub fn route_payment(origin_node: &Node, expected_route: &[&Node], recv_value: u
778779

779780
pub fn route_over_limit(origin_node: &Node, expected_route: &[&Node], recv_value: u64) {
780781
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();
781-
assert_eq!(route.hops.len(), expected_route.len());
782-
for (node, hop) in expected_route.iter().zip(route.hops.iter()) {
782+
assert_eq!(route.paths.len(), 1);
783+
assert_eq!(route.paths[0].len(), expected_route.len());
784+
for (node, hop) in expected_route.iter().zip(route.paths[0].iter()) {
783785
assert_eq!(hop.pubkey, node.node.get_our_node_id());
784786
}
785787

0 commit comments

Comments
 (0)