Skip to content

Commit 5dafa3b

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 66ee854 commit 5dafa3b

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
@@ -414,14 +414,14 @@ pub fn do_test(data: &[u8]) {
414414
let payment_hash = Sha256::hash(&[payment_id; 1]);
415415
payment_id = payment_id.wrapping_add(1);
416416
if let Err(_) = $source.send_payment(Route {
417-
hops: vec![RouteHop {
417+
paths: vec![vec![RouteHop {
418418
pubkey: $dest.0.get_our_node_id(),
419419
node_features: NodeFeatures::empty(),
420420
short_channel_id: $dest.1,
421421
channel_features: ChannelFeatures::empty(),
422422
fee_msat: 5000000,
423423
cltv_expiry_delta: 200,
424-
}],
424+
}]],
425425
}, PaymentHash(payment_hash.into_inner()), None) {
426426
// Probably ran out of funds
427427
test_return!();
@@ -431,7 +431,7 @@ pub fn do_test(data: &[u8]) {
431431
let payment_hash = Sha256::hash(&[payment_id; 1]);
432432
payment_id = payment_id.wrapping_add(1);
433433
if let Err(_) = $source.send_payment(Route {
434-
hops: vec![RouteHop {
434+
paths: vec![vec![RouteHop {
435435
pubkey: $middle.0.get_our_node_id(),
436436
node_features: NodeFeatures::empty(),
437437
short_channel_id: $middle.1,
@@ -445,7 +445,7 @@ pub fn do_test(data: &[u8]) {
445445
channel_features: ChannelFeatures::empty(),
446446
fee_msat: 5000000,
447447
cltv_expiry_delta: 200,
448-
}],
448+
}]],
449449
}, PaymentHash(payment_hash.into_inner()), None) {
450450
// Probably ran out of funds
451451
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};
@@ -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
}
@@ -1191,23 +1191,26 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
11911191
/// If a payment_secret *is* provided, we assume that the invoice had the basic_mpp feature bit
11921192
/// set (either as required or as available).
11931193
pub fn send_payment(&self, route: Route, payment_hash: PaymentHash, payment_secret: Option<&[u8; 32]>) -> Result<(), APIError> {
1194-
if route.hops.len() < 1 || route.hops.len() > 20 {
1195-
return Err(APIError::RouteError{err: "Route didn't go anywhere/had bogus size"});
1194+
if route.paths.len() < 1 || route.paths.len() > 1 {
1195+
return Err(APIError::RouteError{err: "We currently don't support MPP, and we need at least one path"});
1196+
}
1197+
if route.paths[0].len() < 1 || route.paths[0].len() > 20 {
1198+
return Err(APIError::RouteError{err: "Path didn't go anywhere/had bogus size"});
11961199
}
11971200
let our_node_id = self.get_our_node_id();
1198-
for (idx, hop) in route.hops.iter().enumerate() {
1199-
if idx != route.hops.len() - 1 && hop.pubkey == our_node_id {
1200-
return Err(APIError::RouteError{err: "Route went through us but wasn't a simple rebalance loop to us"});
1201+
for (idx, hop) in route.paths[0].iter().enumerate() {
1202+
if idx != route.paths[0].len() - 1 && hop.pubkey == our_node_id {
1203+
return Err(APIError::RouteError{err: "Path went through us but wasn't a simple rebalance loop to us"});
12011204
}
12021205
}
12031206

12041207
let (session_priv, prng_seed) = self.keys_manager.get_onion_rand();
12051208

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

1208-
let onion_keys = secp_call!(onion_utils::construct_onion_keys(&self.secp_ctx, &route, &session_priv),
1211+
let onion_keys = secp_call!(onion_utils::construct_onion_keys(&self.secp_ctx, &route.paths[0], &session_priv),
12091212
APIError::RouteError{err: "Pubkey along hop was maliciously selected"});
1210-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route, payment_secret, cur_height)?;
1213+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], payment_secret, cur_height)?;
12111214
if onion_utils::route_size_insane(&onion_payloads) {
12121215
return Err(APIError::RouteError{err: "Route size too large considering onion data"});
12131216
}
@@ -1218,22 +1221,22 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
12181221
let mut channel_lock = self.channel_state.lock().unwrap();
12191222
let err: Result<(), _> = loop {
12201223

1221-
let id = match channel_lock.short_to_id.get(&route.hops.first().unwrap().short_channel_id) {
1224+
let id = match channel_lock.short_to_id.get(&route.paths[0].first().unwrap().short_channel_id) {
12221225
None => return Err(APIError::ChannelUnavailable{err: "No channel available with first hop!"}),
12231226
Some(id) => id.clone(),
12241227
};
12251228

12261229
let channel_state = &mut *channel_lock;
12271230
if let hash_map::Entry::Occupied(mut chan) = channel_state.by_id.entry(id) {
12281231
match {
1229-
if chan.get().get_their_node_id() != route.hops.first().unwrap().pubkey {
1232+
if chan.get().get_their_node_id() != route.paths[0].first().unwrap().pubkey {
12301233
return Err(APIError::RouteError{err: "Node ID mismatch on first hop!"});
12311234
}
12321235
if !chan.get().is_live() {
12331236
return Err(APIError::ChannelUnavailable{err: "Peer for first hop currently disconnected/pending monitor update!"});
12341237
}
12351238
break_chan_entry!(self, chan.get_mut().send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute {
1236-
route: route.clone(),
1239+
path: route.paths[0].clone(),
12371240
session_priv: session_priv.clone(),
12381241
first_hop_htlc_msat: htlc_msat,
12391242
}, onion_packet), channel_state, chan)
@@ -1249,7 +1252,7 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
12491252
}
12501253

12511254
channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
1252-
node_id: route.hops.first().unwrap().pubkey,
1255+
node_id: route.paths[0].first().unwrap().pubkey,
12531256
updates: msgs::CommitmentUpdate {
12541257
update_add_htlcs: vec![update_add],
12551258
update_fulfill_htlcs: Vec::new(),
@@ -1266,7 +1269,7 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
12661269
return Ok(());
12671270
};
12681271

1269-
match handle_error!(self, err, route.hops.first().unwrap().pubkey, channel_lock) {
1272+
match handle_error!(self, err, route.paths[0].first().unwrap().pubkey, channel_lock) {
12701273
Ok(_) => unreachable!(),
12711274
Err(e) => { Err(APIError::ChannelUnavailable { err: e.err }) }
12721275
}
@@ -1701,7 +1704,7 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
17011704
//between the branches here. We should make this async and move it into the forward HTLCs
17021705
//timer handling.
17031706
match source {
1704-
HTLCSource::OutboundRoute { ref route, .. } => {
1707+
HTLCSource::OutboundRoute { ref path, .. } => {
17051708
log_trace!(self, "Failing outbound payment HTLC with payment_hash {}", log_bytes!(payment_hash.0));
17061709
mem::drop(channel_state_lock);
17071710
match &onion_error {
@@ -1743,7 +1746,7 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
17431746
self.pending_events.lock().unwrap().push(
17441747
events::Event::PaymentFailed {
17451748
payment_hash: payment_hash.clone(),
1746-
rejected_by_dest: route.hops.len() == 1,
1749+
rejected_by_dest: path.len() == 1,
17471750
#[cfg(test)]
17481751
error_code: Some(*failure_code),
17491752
}
@@ -1807,9 +1810,19 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
18071810
let mut channel_state = Some(self.channel_state.lock().unwrap());
18081811
let removed_source = channel_state.as_mut().unwrap().claimable_htlcs.remove(&(payment_hash, *payment_secret));
18091812
if let Some(mut sources) = removed_source {
1813+
assert!(!sources.is_empty());
1814+
let passes_value = if let &Some(ref data) = &sources[0].payment_data {
1815+
assert!(payment_secret.is_some());
1816+
if data.total_msat == expected_amount { true } else { false }
1817+
} else {
1818+
assert!(payment_secret.is_none());
1819+
false
1820+
};
1821+
1822+
let mut one_claimed = false;
18101823
for htlc in sources.drain(..) {
18111824
if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); }
1812-
if htlc.value < expected_amount || htlc.value > expected_amount * 2 {
1825+
if !passes_value && (htlc.value < expected_amount || htlc.value > expected_amount * 2) {
18131826
let mut htlc_msat_data = byte_utils::be64_to_array(htlc.value).to_vec();
18141827
let mut height_data = byte_utils::be32_to_array(self.latest_block_height.load(Ordering::Acquire) as u32).to_vec();
18151828
htlc_msat_data.append(&mut height_data);
@@ -1818,9 +1831,10 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
18181831
HTLCFailReason::Reason { failure_code: 0x4000|15, data: htlc_msat_data });
18191832
} else {
18201833
self.claim_funds_internal(channel_state.take().unwrap(), HTLCSource::PreviousHopData(htlc.src), payment_preimage);
1834+
one_claimed = true;
18211835
}
18221836
}
1823-
true
1837+
one_claimed
18241838
} else { false }
18251839
}
18261840
fn claim_funds_internal(&self, mut channel_state_lock: MutexGuard<ChannelHolder<ChanSigner>>, source: HTLCSource, payment_preimage: PaymentPreimage) {
@@ -3233,9 +3247,9 @@ impl Writeable for HTLCSource {
32333247
0u8.write(writer)?;
32343248
hop_data.write(writer)?;
32353249
},
3236-
&HTLCSource::OutboundRoute { ref route, ref session_priv, ref first_hop_htlc_msat } => {
3250+
&HTLCSource::OutboundRoute { ref path, ref session_priv, ref first_hop_htlc_msat } => {
32373251
1u8.write(writer)?;
3238-
route.write(writer)?;
3252+
path.write(writer)?;
32393253
session_priv.write(writer)?;
32403254
first_hop_htlc_msat.write(writer)?;
32413255
}
@@ -3249,7 +3263,7 @@ impl<R: ::std::io::Read> Readable<R> for HTLCSource {
32493263
match <u8 as Readable<R>>::read(reader)? {
32503264
0 => Ok(HTLCSource::PreviousHopData(Readable::read(reader)?)),
32513265
1 => Ok(HTLCSource::OutboundRoute {
3252-
route: Readable::read(reader)?,
3266+
path: Readable::read(reader)?,
32533267
session_priv: Readable::read(reader)?,
32543268
first_hop_htlc_msat: Readable::read(reader)?,
32553269
}),

lightning/src/ln/functional_test_utils.rs

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

781781
pub fn route_payment<'a, 'b>(origin_node: &Node<'a, 'b>, expected_route: &[&Node<'a, 'b>], recv_value: u64) -> (PaymentPreimage, PaymentHash) {
782782
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();
783-
assert_eq!(route.hops.len(), expected_route.len());
784-
for (node, hop) in expected_route.iter().zip(route.hops.iter()) {
783+
assert_eq!(route.paths.len(), 1);
784+
assert_eq!(route.paths[0].len(), expected_route.len());
785+
for (node, hop) in expected_route.iter().zip(route.paths[0].iter()) {
785786
assert_eq!(hop.pubkey, node.node.get_our_node_id());
786787
}
787788

@@ -790,8 +791,9 @@ pub fn route_payment<'a, 'b>(origin_node: &Node<'a, 'b>, expected_route: &[&Node
790791

791792
pub fn route_over_limit<'a, 'b>(origin_node: &Node<'a, 'b>, expected_route: &[&Node<'a, 'b>], recv_value: u64) {
792793
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();
793-
assert_eq!(route.hops.len(), expected_route.len());
794-
for (node, hop) in expected_route.iter().zip(route.hops.iter()) {
794+
assert_eq!(route.paths.len(), 1);
795+
assert_eq!(route.paths[0].len(), expected_route.len());
796+
for (node, hop) in expected_route.iter().zip(route.paths[0].iter()) {
795797
assert_eq!(hop.pubkey, node.node.get_our_node_id());
796798
}
797799

0 commit comments

Comments
 (0)