Skip to content

Commit f919d6a

Browse files
committed
Implement multipath sends using payment_secret.
This rather dramatically changes the return type of send_payment making it much clearer when resending is safe and allowing us to return a list of Results since different paths may have different return values.
1 parent 9cd702a commit f919d6a

File tree

5 files changed

+233
-167
lines changed

5 files changed

+233
-167
lines changed

lightning/src/ln/chanmon_update_fail_tests.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//! here. See also the chanmon_fail_consistency fuzz test.
55
66
use chain::transaction::OutPoint;
7-
use ln::channelmanager::{RAACommitmentOrder, PaymentPreimage, PaymentHash};
7+
use ln::channelmanager::{RAACommitmentOrder, PaymentPreimage, PaymentHash, PaymentSendFailure};
88
use ln::channelmonitor::ChannelMonitorUpdateErr;
99
use ln::features::InitFeatures;
1010
use ln::msgs;
@@ -30,7 +30,7 @@ fn test_simple_monitor_permanent_update_fail() {
3030
let (_, payment_hash_1) = get_payment_preimage_hash!(&nodes[0]);
3131

3232
*nodes[0].chan_monitor.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::PermanentFailure);
33-
if let Err(APIError::ChannelUnavailable {..}) = nodes[0].node.send_payment(route, payment_hash_1, &None) {} else { panic!(); }
33+
unwrap_send_err!(nodes[0].node.send_payment(route, payment_hash_1, &None), true, APIError::ChannelUnavailable {..}, {});
3434
check_added_monitors!(nodes[0], 2);
3535

3636
let events_1 = nodes[0].node.get_and_clear_pending_msg_events();
@@ -63,7 +63,8 @@ fn do_test_simple_monitor_temporary_update_fail(disconnect: bool) {
6363
let (payment_preimage_1, payment_hash_1) = get_payment_preimage_hash!(&nodes[0]);
6464

6565
*nodes[0].chan_monitor.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure);
66-
if let Err(APIError::MonitorUpdateFailed) = nodes[0].node.send_payment(route.clone(), payment_hash_1, &None) {} else { panic!(); }
66+
67+
unwrap_send_err!(nodes[0].node.send_payment(route.clone(), payment_hash_1, &None), false, APIError::MonitorUpdateFailed, {});
6768
check_added_monitors!(nodes[0], 1);
6869

6970
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
@@ -106,7 +107,7 @@ fn do_test_simple_monitor_temporary_update_fail(disconnect: bool) {
106107
// Now set it to failed again...
107108
let (_, payment_hash_2) = get_payment_preimage_hash!(&nodes[0]);
108109
*nodes[0].chan_monitor.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure);
109-
if let Err(APIError::MonitorUpdateFailed) = nodes[0].node.send_payment(route, payment_hash_2, &None) {} else { panic!(); }
110+
unwrap_send_err!(nodes[0].node.send_payment(route, payment_hash_2, &None), false, APIError::MonitorUpdateFailed, {});
110111
check_added_monitors!(nodes[0], 1);
111112

112113
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
@@ -169,7 +170,7 @@ fn do_test_monitor_temporary_update_fail(disconnect_count: usize) {
169170
let (payment_preimage_2, payment_hash_2) = get_payment_preimage_hash!(nodes[0]);
170171

171172
*nodes[0].chan_monitor.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure);
172-
if let Err(APIError::MonitorUpdateFailed) = nodes[0].node.send_payment(route.clone(), payment_hash_2, &None) {} else { panic!(); }
173+
unwrap_send_err!(nodes[0].node.send_payment(route.clone(), payment_hash_2, &None), false, APIError::MonitorUpdateFailed, {});
173174
check_added_monitors!(nodes[0], 1);
174175

175176
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());

lightning/src/ln/channelmanager.rs

Lines changed: 171 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -446,15 +446,6 @@ const CHECK_CLTV_EXPIRY_SANITY: u32 = CLTV_EXPIRY_DELTA as u32 - LATENCY_GRACE_P
446446
#[allow(dead_code)]
447447
const CHECK_CLTV_EXPIRY_SANITY_2: u32 = CLTV_EXPIRY_DELTA as u32 - LATENCY_GRACE_PERIOD_BLOCKS - 2*CLTV_CLAIM_BUFFER;
448448

449-
macro_rules! secp_call {
450-
( $res: expr, $err: expr ) => {
451-
match $res {
452-
Ok(key) => key,
453-
Err(_) => return Err($err),
454-
}
455-
};
456-
}
457-
458449
/// Details of a channel, as returned by ChannelManager::list_channels and ChannelManager::list_usable_channels
459450
pub struct ChannelDetails {
460451
/// The channel's ID (prior to funding transaction generation, this is a random 32 bytes,
@@ -491,6 +482,42 @@ pub struct ChannelDetails {
491482
pub is_live: bool,
492483
}
493484

485+
/// If a payment fails to send, it can be in one of several states. This enum is returned as the
486+
/// Err() type describing which state the payment is in, see the description of individual enum
487+
/// states for more.
488+
#[derive(Debug)]
489+
pub enum PaymentSendFailure {
490+
/// A parameter which was passed to send_payment was invalid, preventing us from attempting to
491+
/// send the payment at all. No channel state has been changed or messages sent to peers, and
492+
/// once you've changed the parameter at error, you can freely retry the payment in full.
493+
ParameterError(APIError),
494+
/// A parameter in a single path which was passed to send_payment was invalid, preventing us
495+
/// from attempting to send the payment at all. No channel state has been changed or messages
496+
/// sent to peers, and once you've changed the parameter at error, you can freely retry the
497+
/// payment in full.
498+
///
499+
/// The results here are ordered the same as the paths in the route object which was passed to
500+
/// send_payment.
501+
PathParameterError(Vec<Result<(), APIError>>),
502+
/// All paths which were attempted failed to send, with no channel state change taking place.
503+
/// You can freely retry the payment in full (though you probably want to do so over different
504+
/// paths than the ones selected).
505+
AllFailedRetrySafe(Vec<APIError>),
506+
/// Some paths which were attempted failed to send, though possibly not all. At least some
507+
/// paths have irrevocably committed to the HTLC and retrying the payment in full would result
508+
/// in over-/re-payment.
509+
///
510+
/// The results here are ordered the same as the paths in the route object which was passed to
511+
/// send_payment, and any Errs which are not APIError::MonitorUpdateFailed can be safely
512+
/// retried (though there is currently no API with which to do so).
513+
///
514+
/// Any entries which contain Err(APIError::MonitorUpdateFailed) or Ok(()) MUST NOT be retried
515+
/// as they will result in over-/re-payment. These HTLCs all either successfully sent (in the
516+
/// case of Ok(())) or will send once channel_monitor_updated is called on the next-hop channel
517+
/// with the latest update_id.
518+
PartialFailure(Vec<Result<(), APIError>>),
519+
}
520+
494521
macro_rules! handle_error {
495522
($self: ident, $internal: expr, $their_node_id: expr) => {
496523
match $internal {
@@ -1207,20 +1234,24 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
12071234
/// payment_preimage tracking (which you should already be doing as they represent "proof of
12081235
/// payment") and prevent double-sends yourself.
12091236
///
1210-
/// May generate a SendHTLCs message event on success, which should be relayed.
1237+
/// May generate SendHTLCs message(s) event on success, which should be relayed.
1238+
///
1239+
/// Each path may have a different return value, and PaymentSendValue may return a Vec with
1240+
/// each entry matching the corresponding-index entry in the route paths, see
1241+
/// PaymentSendFailure for more info.
12111242
///
1212-
/// Raises APIError::RoutError when invalid route or forward parameter
1213-
/// (cltv_delta, fee, node public key) is specified.
1214-
/// Raises APIError::ChannelUnavailable if the next-hop channel is not available for updates
1215-
/// (including due to previous monitor update failure or new permanent monitor update failure).
1216-
/// Raised APIError::MonitorUpdateFailed if a new monitor update failure prevented sending the
1217-
/// relevant updates.
1243+
/// In general, a path may raise:
1244+
/// * APIError::RouteError when an invalid route or forwarding parameter (cltv_delta, fee,
1245+
/// node public key) is specified.
1246+
/// * APIError::ChannelUnavailable if the next-hop channel is not available for updates
1247+
/// (including due to previous monitor update failure or new permanent monitor update
1248+
/// failure).
1249+
/// * APIError::MonitorUpdateFailed if a new monitor update failure prevented sending the
1250+
/// relevant updates.
12181251
///
1219-
/// In case of APIError::RouteError/APIError::ChannelUnavailable, the payment send has failed
1220-
/// and you may wish to retry via a different route immediately.
1221-
/// In case of APIError::MonitorUpdateFailed, the commitment update has been irrevocably
1222-
/// committed on our end and we're just waiting for a monitor update to send it. Do NOT retry
1223-
/// the payment via a different route unless you intend to pay twice!
1252+
/// Note that depending on the type of the PaymentSendFailure the HTLC may have been
1253+
/// irrevocably committed to on our end. In such a case, do NOT retry the payment with a
1254+
/// different route unless you intend to pay twice!
12241255
///
12251256
/// payment_secret is unrelated to payment_hash (or PaymentPreimage) and exists to authenticate
12261257
/// the sender to the recipient and prevent payment-probing (deanonymization) attacks. For
@@ -1229,87 +1260,139 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
12291260
/// If a payment_secret *is* provided, we assume that the invoice had the payment_secret feature
12301261
/// bit set (either as required or as available). If multiple paths are present in the Route,
12311262
/// we assume the invoice had the basic_mpp feature set.
1232-
pub fn send_payment(&self, route: Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>) -> Result<(), APIError> {
1233-
if route.paths.len() < 1 || route.paths.len() > 1 {
1234-
return Err(APIError::RouteError{err: "We currently don't support MPP, and we need at least one path"});
1263+
pub fn send_payment(&self, route: Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>) -> Result<(), PaymentSendFailure> {
1264+
if route.paths.len() < 1 {
1265+
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "There must be at least one path to send over"}));
12351266
}
1236-
if route.paths[0].len() < 1 || route.paths[0].len() > 20 {
1237-
return Err(APIError::RouteError{err: "Path didn't go anywhere/had bogus size"});
1267+
if route.paths.len() > 10 {
1268+
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "Sending over more than 10 paths is not currently supported"}));
12381269
}
1270+
let mut total_value = 0;
12391271
let our_node_id = self.get_our_node_id();
1240-
for (idx, hop) in route.paths[0].iter().enumerate() {
1241-
if idx != route.paths[0].len() - 1 && hop.pubkey == our_node_id {
1242-
return Err(APIError::RouteError{err: "Path went through us but wasn't a simple rebalance loop to us"});
1272+
let mut path_errs = Vec::with_capacity(route.paths.len());
1273+
'path_check: for path in route.paths.iter() {
1274+
if path.len() < 1 || path.len() > 20 {
1275+
path_errs.push(Err(APIError::RouteError{err: "Path didn't go anywhere/had bogus size"}));
1276+
continue 'path_check;
1277+
}
1278+
for (idx, hop) in path.iter().enumerate() {
1279+
if idx != path.len() - 1 && hop.pubkey == our_node_id {
1280+
path_errs.push(Err(APIError::RouteError{err: "Path went through us but wasn't a simple rebalance loop to us"}));
1281+
continue 'path_check;
1282+
}
12431283
}
1284+
total_value += path.last().unwrap().fee_msat;
1285+
path_errs.push(Ok(()));
1286+
}
1287+
if path_errs.iter().any(|e| e.is_err()) {
1288+
return Err(PaymentSendFailure::PathParameterError(path_errs));
12441289
}
1245-
1246-
let (session_priv, prng_seed) = self.keys_manager.get_onion_rand();
12471290

12481291
let cur_height = self.latest_block_height.load(Ordering::Acquire) as u32 + 1;
1292+
let mut results = Vec::new();
1293+
'path_loop: for path in route.paths.iter() {
1294+
macro_rules! check_res_push {
1295+
($res: expr) => { match $res {
1296+
Ok(r) => r,
1297+
Err(e) => {
1298+
results.push(Err(e));
1299+
continue 'path_loop;
1300+
},
1301+
}
1302+
}
1303+
}
12491304

1250-
let onion_keys = secp_call!(onion_utils::construct_onion_keys(&self.secp_ctx, &route.paths[0], &session_priv),
1251-
APIError::RouteError{err: "Pubkey along hop was maliciously selected"});
1252-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], payment_secret, cur_height)?;
1253-
if onion_utils::route_size_insane(&onion_payloads) {
1254-
return Err(APIError::RouteError{err: "Route size too large considering onion data"});
1255-
}
1256-
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, &payment_hash);
1305+
log_trace!(self, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id);
1306+
let (session_priv, prng_seed) = self.keys_manager.get_onion_rand();
12571307

1258-
let _ = self.total_consistency_lock.read().unwrap();
1308+
let onion_keys = check_res_push!(onion_utils::construct_onion_keys(&self.secp_ctx, &path, &session_priv)
1309+
.map_err(|_| APIError::RouteError{err: "Pubkey along hop was maliciously selected"}));
1310+
let (onion_payloads, htlc_msat, htlc_cltv) = check_res_push!(onion_utils::build_onion_payloads(&path, total_value, payment_secret, cur_height));
1311+
if onion_utils::route_size_insane(&onion_payloads) {
1312+
check_res_push!(Err(APIError::RouteError{err: "Route size too large considering onion data"}));
1313+
}
1314+
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, &payment_hash);
12591315

1260-
let err: Result<(), _> = loop {
1261-
let mut channel_lock = self.channel_state.lock().unwrap();
1262-
let id = match channel_lock.short_to_id.get(&route.paths[0].first().unwrap().short_channel_id) {
1263-
None => return Err(APIError::ChannelUnavailable{err: "No channel available with first hop!"}),
1264-
Some(id) => id.clone(),
1265-
};
1316+
let _ = self.total_consistency_lock.read().unwrap();
12661317

1267-
let channel_state = &mut *channel_lock;
1268-
if let hash_map::Entry::Occupied(mut chan) = channel_state.by_id.entry(id) {
1269-
match {
1270-
if chan.get().get_their_node_id() != route.paths[0].first().unwrap().pubkey {
1271-
return Err(APIError::RouteError{err: "Node ID mismatch on first hop!"});
1272-
}
1273-
if !chan.get().is_live() {
1274-
return Err(APIError::ChannelUnavailable{err: "Peer for first hop currently disconnected/pending monitor update!"});
1275-
}
1276-
break_chan_entry!(self, chan.get_mut().send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute {
1277-
path: route.paths[0].clone(),
1278-
session_priv: session_priv.clone(),
1279-
first_hop_htlc_msat: htlc_msat,
1280-
}, onion_packet), channel_state, chan)
1281-
} {
1282-
Some((update_add, commitment_signed, monitor_update)) => {
1283-
if let Err(e) = self.monitor.update_monitor(chan.get().get_funding_txo().unwrap(), monitor_update) {
1284-
maybe_break_monitor_err!(self, e, channel_state, chan, RAACommitmentOrder::CommitmentFirst, false, true);
1285-
// Note that MonitorUpdateFailed here indicates (per function docs)
1286-
// that we will resent the commitment update once we unfree monitor
1287-
// updating, so we have to take special care that we don't return
1288-
// something else in case we will resend later!
1289-
return Err(APIError::MonitorUpdateFailed);
1318+
let err: Result<(), _> = loop {
1319+
let mut channel_lock = self.channel_state.lock().unwrap();
1320+
let id = match channel_lock.short_to_id.get(&path.first().unwrap().short_channel_id) {
1321+
None => check_res_push!(Err(APIError::ChannelUnavailable{err: "No channel available with first hop!"})),
1322+
Some(id) => id.clone(),
1323+
};
1324+
1325+
let channel_state = &mut *channel_lock;
1326+
if let hash_map::Entry::Occupied(mut chan) = channel_state.by_id.entry(id) {
1327+
match {
1328+
if chan.get().get_their_node_id() != path.first().unwrap().pubkey {
1329+
check_res_push!(Err(APIError::RouteError{err: "Node ID mismatch on first hop!"}));
12901330
}
1331+
if !chan.get().is_live() {
1332+
check_res_push!(Err(APIError::ChannelUnavailable{err: "Peer for first hop currently disconnected/pending monitor update!"}));
1333+
}
1334+
break_chan_entry!(self, chan.get_mut().send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute {
1335+
path: path.clone(),
1336+
session_priv: session_priv.clone(),
1337+
first_hop_htlc_msat: htlc_msat,
1338+
}, onion_packet), channel_state, chan)
1339+
} {
1340+
Some((update_add, commitment_signed, monitor_update)) => {
1341+
if let Err(e) = self.monitor.update_monitor(chan.get().get_funding_txo().unwrap(), monitor_update) {
1342+
maybe_break_monitor_err!(self, e, channel_state, chan, RAACommitmentOrder::CommitmentFirst, false, true);
1343+
// Note that MonitorUpdateFailed here indicates (per function docs)
1344+
// that we will resend the commitment update once monitor updating
1345+
// is restored. Therefore, we must return an error indicating that
1346+
// it is unsafe to retry the payment wholesale, which we do in the
1347+
// next check for MonitorUpdateFailed, below.
1348+
check_res_push!(Err(APIError::MonitorUpdateFailed));
1349+
}
12911350

1292-
channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
1293-
node_id: route.paths[0].first().unwrap().pubkey,
1294-
updates: msgs::CommitmentUpdate {
1295-
update_add_htlcs: vec![update_add],
1296-
update_fulfill_htlcs: Vec::new(),
1297-
update_fail_htlcs: Vec::new(),
1298-
update_fail_malformed_htlcs: Vec::new(),
1299-
update_fee: None,
1300-
commitment_signed,
1301-
},
1302-
});
1303-
},
1304-
None => {},
1305-
}
1306-
} else { unreachable!(); }
1307-
return Ok(());
1308-
};
1351+
channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
1352+
node_id: path.first().unwrap().pubkey,
1353+
updates: msgs::CommitmentUpdate {
1354+
update_add_htlcs: vec![update_add],
1355+
update_fulfill_htlcs: Vec::new(),
1356+
update_fail_htlcs: Vec::new(),
1357+
update_fail_malformed_htlcs: Vec::new(),
1358+
update_fee: None,
1359+
commitment_signed,
1360+
},
1361+
});
1362+
},
1363+
None => {},
1364+
}
1365+
} else { unreachable!(); }
1366+
results.push(Ok(()));
1367+
continue 'path_loop;
1368+
};
13091369

1310-
match handle_error!(self, err, route.paths[0].first().unwrap().pubkey) {
1311-
Ok(_) => unreachable!(),
1312-
Err(e) => { Err(APIError::ChannelUnavailable { err: e.err }) }
1370+
match handle_error!(self, err, path.first().unwrap().pubkey) {
1371+
Ok(_) => unreachable!(),
1372+
Err(e) => {
1373+
check_res_push!(Err(APIError::ChannelUnavailable { err: e.err }));
1374+
},
1375+
}
1376+
}
1377+
let mut has_ok = false;
1378+
let mut has_err = false;
1379+
for res in results.iter() {
1380+
if res.is_ok() { has_ok = true; }
1381+
if res.is_err() { has_err = true; }
1382+
if let &Err(APIError::MonitorUpdateFailed) = res {
1383+
// MonitorUpdateFailed is inherently unsafe to retry, so we call it a
1384+
// PartialFailure.
1385+
has_err = true;
1386+
has_ok = true;
1387+
break;
1388+
}
1389+
}
1390+
if has_err && has_ok {
1391+
Err(PaymentSendFailure::PartialFailure(results))
1392+
} else if has_err {
1393+
Err(PaymentSendFailure::AllFailedRetrySafe(results.drain(..).map(|r| r.unwrap_err()).collect()))
1394+
} else {
1395+
Ok(())
13131396
}
13141397
}
13151398

0 commit comments

Comments
 (0)