Skip to content

Commit e0f3a03

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 fd46193 commit e0f3a03

File tree

5 files changed

+212
-167
lines changed

5 files changed

+212
-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: 151 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -439,15 +439,6 @@ const CHECK_CLTV_EXPIRY_SANITY: u32 = CLTV_EXPIRY_DELTA as u32 - LATENCY_GRACE_P
439439
#[allow(dead_code)]
440440
const CHECK_CLTV_EXPIRY_SANITY_2: u32 = CLTV_EXPIRY_DELTA as u32 - LATENCY_GRACE_PERIOD_BLOCKS - 2*CLTV_CLAIM_BUFFER;
441441

442-
macro_rules! secp_call {
443-
( $res: expr, $err: expr ) => {
444-
match $res {
445-
Ok(key) => key,
446-
Err(_) => return Err($err),
447-
}
448-
};
449-
}
450-
451442
/// Details of a channel, as returned by ChannelManager::list_channels and ChannelManager::list_usable_channels
452443
pub struct ChannelDetails {
453444
/// The channel's ID (prior to funding transaction generation, this is a random 32 bytes,
@@ -484,6 +475,32 @@ pub struct ChannelDetails {
484475
pub is_live: bool,
485476
}
486477

478+
/// If a payment fails to send, it can be in one of several states. This enum is returned as the
479+
/// Err() type describing which state the payment is in, see the description of individual enum
480+
/// states for more.
481+
#[derive(Debug)]
482+
pub enum PaymentSendFailure {
483+
/// A parameter which was passed to send_payment was invalid, preventing us from attempting to
484+
/// send the payment at all. No channel state has been changed or messages sent to peers, and
485+
/// once you've changed the parameter at error, you can freely retry the payment in full.
486+
ParameterError(APIError),
487+
/// All paths which were attempted failed to send, with no channel state change taking place.
488+
/// You can freely retry the payment in full (though you probably want to do so over different
489+
/// paths than the ones selected).
490+
AllFailedRetrySafe(Vec<APIError>),
491+
/// Some paths which were attempted failed to send, though possibly not all. At least some
492+
/// paths have irrevocably committed to the HTLC and retrying the payment in full would result
493+
/// in over-/re-payment.
494+
///
495+
/// The results here are ordered the same as the paths in the route object which was passed to
496+
/// send_payment, and any Errs which are not APIError::MonitorUpdateFailed can be safely
497+
/// retried.
498+
///
499+
/// Any entries which contain Err(APIError::MonitorUpdateFailed) or Ok(()) MUST NOT be retried
500+
/// as they will result in over-/re-payment.
501+
PartialFailure(Vec<Result<(), APIError>>),
502+
}
503+
487504
macro_rules! handle_error {
488505
($self: ident, $internal: expr, $their_node_id: expr, $locked_channel_state: expr) => {
489506
match $internal {
@@ -1180,109 +1197,154 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
11801197
/// payment_preimage tracking (which you should already be doing as they represent "proof of
11811198
/// payment") and prevent double-sends yourself.
11821199
///
1183-
/// May generate a SendHTLCs message event on success, which should be relayed.
1200+
/// May generate SendHTLCs message(s) event on success, which should be relayed.
1201+
///
1202+
/// Each path may have a different return value, and PaymentSendValue may return a Vec with
1203+
/// each entry matching the corresponding-index entry in the route paths.
11841204
///
1185-
/// Raises APIError::RoutError when invalid route or forward parameter
1186-
/// (cltv_delta, fee, node public key) is specified.
1187-
/// Raises APIError::ChannelUnavailable if the next-hop channel is not available for updates
1188-
/// (including due to previous monitor update failure or new permanent monitor update failure).
1189-
/// Raised APIError::MonitorUpdateFailed if a new monitor update failure prevented sending the
1190-
/// relevant updates.
1205+
/// In general, a path may raise:
1206+
/// * APIError::RouteError when an invalid route or forwarding parameter (cltv_delta, fee,
1207+
/// node public key) is specified.
1208+
/// * APIError::ChannelUnavailable if the next-hop channel is not available for updates
1209+
/// (including due to previous monitor update failure or new permanent monitor update
1210+
/// failure).
1211+
/// * APIError::MonitorUpdateFailed if a new monitor update failure prevented sending the
1212+
/// relevant updates.
11911213
///
1192-
/// In case of APIError::RouteError/APIError::ChannelUnavailable, the payment send has failed
1193-
/// and you may wish to retry via a different route immediately.
1194-
/// In case of APIError::MonitorUpdateFailed, the commitment update has been irrevocably
1195-
/// committed on our end and we're just waiting for a monitor update to send it. Do NOT retry
1196-
/// the payment via a different route unless you intend to pay twice!
1214+
/// Note that depending on the type of the PaymentSendFailure the HTLC may have been
1215+
/// irrevocably committed to on our end. In such a case, do NOT retry the payment with a
1216+
/// different route unless you intend to pay twice!
11971217
///
11981218
/// payment_secret is unrelated to payment_hash (or PaymentPreimage) and exists to authenticate
11991219
/// the sender to the recipient and prevent payment-probing (deanonymization) attacks. For
12001220
/// newer nodes, it will be provided to you in the invoice. If you do not have one, the Route
12011221
/// must not contain multiple paths as otherwise the multipath data cannot be sent.
12021222
/// If a payment_secret *is* provided, we assume that the invoice had the basic_mpp feature bit
12031223
/// set (either as required or as available).
1204-
pub fn send_payment(&self, route: Route, payment_hash: PaymentHash, payment_secret: Option<&[u8; 32]>) -> Result<(), APIError> {
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"});
1224+
pub fn send_payment(&self, route: Route, payment_hash: PaymentHash, payment_secret: Option<&[u8; 32]>) -> Result<(), PaymentSendFailure> {
1225+
if route.paths.len() < 1 {
1226+
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "There must be at least one path to send over"}));
12071227
}
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"});
1228+
if route.paths.len() > 10 {
1229+
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "Sending over more than 10 paths is not currently supported"}));
12101230
}
1231+
let mut total_value = 0;
12111232
let our_node_id = self.get_our_node_id();
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"});
1233+
for path in route.paths.iter() {
1234+
if path.len() < 1 || path.len() > 20 {
1235+
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "Path didn't go anywhere/had bogus size"}));
1236+
}
1237+
for (idx, hop) in path.iter().enumerate() {
1238+
if idx != path.len() - 1 && hop.pubkey == our_node_id {
1239+
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "Path went through us but wasn't a simple rebalance loop to us"}));
1240+
}
12151241
}
1242+
total_value += path.last().unwrap().fee_msat;
12161243
}
1217-
1218-
let (session_priv, prng_seed) = self.keys_manager.get_onion_rand();
1219-
12201244
let cur_height = self.latest_block_height.load(Ordering::Acquire) as u32 + 1;
1245+
let mut results = Vec::new();
1246+
'path_loop: for path in route.paths.iter() {
1247+
macro_rules! check_res_push {
1248+
($res: expr) => { match $res {
1249+
Ok(r) => r,
1250+
Err(e) => {
1251+
results.push(Err(e));
1252+
continue 'path_loop;
1253+
},
1254+
}
1255+
}
1256+
}
12211257

1222-
let onion_keys = secp_call!(onion_utils::construct_onion_keys(&self.secp_ctx, &route.paths[0], &session_priv),
1223-
APIError::RouteError{err: "Pubkey along hop was maliciously selected"});
1224-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], payment_secret, cur_height)?;
1225-
if onion_utils::route_size_insane(&onion_payloads) {
1226-
return Err(APIError::RouteError{err: "Route size too large considering onion data"});
1227-
}
1228-
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, &payment_hash);
1258+
log_trace!(self, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id);
1259+
let (session_priv, prng_seed) = self.keys_manager.get_onion_rand();
12291260

1230-
let _ = self.total_consistency_lock.read().unwrap();
1261+
let onion_keys = check_res_push!(onion_utils::construct_onion_keys(&self.secp_ctx, &path, &session_priv)
1262+
.map_err(|_| APIError::RouteError{err: "Pubkey along hop was maliciously selected"}));
1263+
let (onion_payloads, htlc_msat, htlc_cltv) = check_res_push!(onion_utils::build_onion_payloads(&path, total_value, payment_secret, cur_height));
1264+
if onion_utils::route_size_insane(&onion_payloads) {
1265+
check_res_push!(Err(APIError::RouteError{err: "Route size too large considering onion data"}));
1266+
}
1267+
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, &payment_hash);
12311268

1232-
let mut channel_lock = self.channel_state.lock().unwrap();
1233-
let err: Result<(), _> = loop {
1269+
let _ = self.total_consistency_lock.read().unwrap();
12341270

1235-
let id = match channel_lock.short_to_id.get(&route.paths[0].first().unwrap().short_channel_id) {
1236-
None => return Err(APIError::ChannelUnavailable{err: "No channel available with first hop!"}),
1237-
Some(id) => id.clone(),
1238-
};
1271+
let mut channel_lock = self.channel_state.lock().unwrap();
1272+
let err: Result<(), _> = loop {
1273+
let id = match channel_lock.short_to_id.get(&path.first().unwrap().short_channel_id) {
1274+
None => check_res_push!(Err(APIError::ChannelUnavailable{err: "No channel available with first hop!"})),
1275+
Some(id) => id.clone(),
1276+
};
12391277

1240-
let channel_state = &mut *channel_lock;
1241-
if let hash_map::Entry::Occupied(mut chan) = channel_state.by_id.entry(id) {
1242-
match {
1243-
if chan.get().get_their_node_id() != route.paths[0].first().unwrap().pubkey {
1244-
return Err(APIError::RouteError{err: "Node ID mismatch on first hop!"});
1245-
}
1246-
if !chan.get().is_live() {
1247-
return Err(APIError::ChannelUnavailable{err: "Peer for first hop currently disconnected/pending monitor update!"});
1248-
}
1249-
break_chan_entry!(self, chan.get_mut().send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute {
1250-
path: route.paths[0].clone(),
1251-
session_priv: session_priv.clone(),
1252-
first_hop_htlc_msat: htlc_msat,
1253-
}, onion_packet), channel_state, chan)
1254-
} {
1255-
Some((update_add, commitment_signed, monitor_update)) => {
1256-
if let Err(e) = self.monitor.update_monitor(chan.get().get_funding_txo().unwrap(), monitor_update) {
1257-
maybe_break_monitor_err!(self, e, channel_state, chan, RAACommitmentOrder::CommitmentFirst, false, true);
1258-
// Note that MonitorUpdateFailed here indicates (per function docs)
1259-
// that we will resent the commitment update once we unfree monitor
1260-
// updating, so we have to take special care that we don't return
1261-
// something else in case we will resend later!
1262-
return Err(APIError::MonitorUpdateFailed);
1278+
let channel_state = &mut *channel_lock;
1279+
if let hash_map::Entry::Occupied(mut chan) = channel_state.by_id.entry(id) {
1280+
match {
1281+
if chan.get().get_their_node_id() != path.first().unwrap().pubkey {
1282+
check_res_push!(Err(APIError::RouteError{err: "Node ID mismatch on first hop!"}));
1283+
}
1284+
if !chan.get().is_live() {
1285+
check_res_push!(Err(APIError::ChannelUnavailable{err: "Peer for first hop currently disconnected/pending monitor update!"}));
12631286
}
1287+
break_chan_entry!(self, chan.get_mut().send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute {
1288+
path: path.clone(),
1289+
session_priv: session_priv.clone(),
1290+
first_hop_htlc_msat: htlc_msat,
1291+
}, onion_packet), channel_state, chan)
1292+
} {
1293+
Some((update_add, commitment_signed, monitor_update)) => {
1294+
if let Err(e) = self.monitor.update_monitor(chan.get().get_funding_txo().unwrap(), monitor_update) {
1295+
maybe_break_monitor_err!(self, e, channel_state, chan, RAACommitmentOrder::CommitmentFirst, false, true);
1296+
// Note that MonitorUpdateFailed here indicates (per function docs)
1297+
// that we will resent the commitment update once we unfree monitor
1298+
// updating, so we have to take special care that we don't return
1299+
// something else in case we will resend later!
1300+
check_res_push!(Err(APIError::MonitorUpdateFailed));
1301+
}
12641302

1265-
channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
1266-
node_id: route.paths[0].first().unwrap().pubkey,
1267-
updates: msgs::CommitmentUpdate {
1268-
update_add_htlcs: vec![update_add],
1269-
update_fulfill_htlcs: Vec::new(),
1270-
update_fail_htlcs: Vec::new(),
1271-
update_fail_malformed_htlcs: Vec::new(),
1272-
update_fee: None,
1273-
commitment_signed,
1274-
},
1275-
});
1276-
},
1277-
None => {},
1278-
}
1279-
} else { unreachable!(); }
1280-
return Ok(());
1281-
};
1303+
channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
1304+
node_id: path.first().unwrap().pubkey,
1305+
updates: msgs::CommitmentUpdate {
1306+
update_add_htlcs: vec![update_add],
1307+
update_fulfill_htlcs: Vec::new(),
1308+
update_fail_htlcs: Vec::new(),
1309+
update_fail_malformed_htlcs: Vec::new(),
1310+
update_fee: None,
1311+
commitment_signed,
1312+
},
1313+
});
1314+
},
1315+
None => {},
1316+
}
1317+
} else { unreachable!(); }
1318+
results.push(Ok(()));
1319+
continue 'path_loop;
1320+
};
12821321

1283-
match handle_error!(self, err, route.paths[0].first().unwrap().pubkey, channel_lock) {
1284-
Ok(_) => unreachable!(),
1285-
Err(e) => { Err(APIError::ChannelUnavailable { err: e.err }) }
1322+
match handle_error!(self, err, path.first().unwrap().pubkey, channel_lock) {
1323+
Ok(_) => unreachable!(),
1324+
Err(e) => {
1325+
check_res_push!(Err(APIError::ChannelUnavailable { err: e.err }));
1326+
},
1327+
}
1328+
}
1329+
let mut has_ok = false;
1330+
let mut has_err = false;
1331+
for res in results.iter() {
1332+
if res.is_ok() { has_ok = true; }
1333+
if res.is_err() { has_err = true; }
1334+
if let &Err(APIError::MonitorUpdateFailed) = res {
1335+
// MonitorUpdateFailed is inherently unsafe to retry, so we call it a
1336+
// PartialFailure.
1337+
has_err = true;
1338+
has_ok = true;
1339+
break;
1340+
}
1341+
}
1342+
if has_err && has_ok {
1343+
Err(PaymentSendFailure::PartialFailure(results))
1344+
} else if has_err {
1345+
Err(PaymentSendFailure::AllFailedRetrySafe(results.drain(..).map(|r| r.unwrap_err()).collect()))
1346+
} else {
1347+
Ok(())
12861348
}
12871349
}
12881350

lightning/src/ln/functional_test_utils.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use chain::chaininterface;
55
use chain::transaction::OutPoint;
66
use chain::keysinterface::KeysInterface;
7-
use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentPreimage, PaymentHash};
7+
use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentPreimage, PaymentHash, PaymentSendFailure};
88
use ln::channelmonitor::{ChannelMonitor, ManyChannelMonitor};
99
use ln::router::{Route, Router, RouterReadArgs};
1010
use ln::features::InitFeatures;
@@ -273,6 +273,28 @@ macro_rules! get_local_commitment_txn {
273273
}
274274
}
275275

276+
macro_rules! unwrap_send_err {
277+
($res: expr, $all_failed: expr, $type: pat, $check: expr) => {
278+
match &$res {
279+
&Err(PaymentSendFailure::AllFailedRetrySafe(ref fails)) if $all_failed => {
280+
assert_eq!(fails.len(), 1);
281+
match fails[0] {
282+
$type => { $check },
283+
_ => panic!(),
284+
}
285+
},
286+
&Err(PaymentSendFailure::PartialFailure(ref fails)) if !$all_failed => {
287+
assert_eq!(fails.len(), 1);
288+
match fails[0] {
289+
Err($type) => { $check },
290+
_ => panic!(),
291+
}
292+
},
293+
_ => panic!(),
294+
}
295+
}
296+
}
297+
276298
pub fn create_funding_transaction<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, expected_chan_value: u64, expected_user_chan_id: u64) -> ([u8; 32], Transaction, OutPoint) {
277299
let chan_id = *node.network_chan_count.borrow();
278300

@@ -915,12 +937,8 @@ pub fn route_over_limit<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_rou
915937
}
916938

917939
let (_, our_payment_hash) = get_payment_preimage_hash!(origin_node);
918-
919-
let err = origin_node.node.send_payment(route, our_payment_hash, None).err().unwrap();
920-
match err {
921-
APIError::ChannelUnavailable{err} => assert_eq!(err, "Cannot send value that would put us over the max HTLC value in flight our peer will accept"),
922-
_ => panic!("Unknown error variants"),
923-
};
940+
unwrap_send_err!(origin_node.node.send_payment(route, our_payment_hash, None), true, APIError::ChannelUnavailable { err },
941+
assert_eq!(err, "Cannot send value that would put us over the max HTLC value in flight our peer will accept"));
924942
}
925943

926944
pub fn send_payment<'a, 'b, 'c>(origin: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], recv_value: u64, expected_value: u64) {

0 commit comments

Comments
 (0)