Skip to content

Commit ba403ad

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 5dafa3b commit ba403ad

File tree

5 files changed

+210
-160
lines changed

5 files changed

+210
-160
lines changed

lightning/src/ln/chanmon_update_fail_tests.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! There are a bunch of these as their handling is relatively error-prone so they are split out
44
//! here. See also the chanmon_fail_consistency fuzz test.
55
6-
use ln::channelmanager::{RAACommitmentOrder, PaymentPreimage, PaymentHash};
6+
use ln::channelmanager::{RAACommitmentOrder, PaymentPreimage, PaymentHash, PaymentSendFailure};
77
use ln::channelmonitor::ChannelMonitorUpdateErr;
88
use ln::features::InitFeatures;
99
use ln::msgs;
@@ -28,7 +28,7 @@ fn test_simple_monitor_permanent_update_fail() {
2828
let (_, payment_hash_1) = get_payment_preimage_hash!(&nodes[0]);
2929

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

3434
let events_1 = nodes[0].node.get_and_clear_pending_msg_events();
@@ -60,7 +60,8 @@ fn do_test_simple_monitor_temporary_update_fail(disconnect: bool) {
6060
let (payment_preimage_1, payment_hash_1) = get_payment_preimage_hash!(&nodes[0]);
6161

6262
*nodes[0].chan_monitor.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure);
63-
if let Err(APIError::MonitorUpdateFailed) = nodes[0].node.send_payment(route.clone(), payment_hash_1, None) {} else { panic!(); }
63+
64+
unwrap_send_err!(nodes[0].node.send_payment(route.clone(), payment_hash_1, None), false, APIError::MonitorUpdateFailed, {});
6465
check_added_monitors!(nodes[0], 1);
6566

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

108109
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
@@ -165,7 +166,7 @@ fn do_test_monitor_temporary_update_fail(disconnect_count: usize) {
165166
let (payment_preimage_2, payment_hash_2) = get_payment_preimage_hash!(nodes[0]);
166167

167168
*nodes[0].chan_monitor.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure);
168-
if let Err(APIError::MonitorUpdateFailed) = nodes[0].node.send_payment(route.clone(), payment_hash_2, None) {} else { panic!(); }
169+
unwrap_send_err!(nodes[0].node.send_payment(route.clone(), payment_hash_2, None), false, APIError::MonitorUpdateFailed, {});
169170
check_added_monitors!(nodes[0], 1);
170171

171172
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
@@ -430,15 +430,6 @@ const CHECK_CLTV_EXPIRY_SANITY: u32 = CLTV_EXPIRY_DELTA as u32 - LATENCY_GRACE_P
430430
#[allow(dead_code)]
431431
const CHECK_CLTV_EXPIRY_SANITY_2: u32 = CLTV_EXPIRY_DELTA as u32 - LATENCY_GRACE_PERIOD_BLOCKS - 2*CLTV_CLAIM_BUFFER;
432432

433-
macro_rules! secp_call {
434-
( $res: expr, $err: expr ) => {
435-
match $res {
436-
Ok(key) => key,
437-
Err(_) => return Err($err),
438-
}
439-
};
440-
}
441-
442433
/// Details of a channel, as returned by ChannelManager::list_channels and ChannelManager::list_usable_channels
443434
pub struct ChannelDetails {
444435
/// The channel's ID (prior to funding transaction generation, this is a random 32 bytes,
@@ -475,6 +466,32 @@ pub struct ChannelDetails {
475466
pub is_live: bool,
476467
}
477468

469+
/// If a payment fails to send, it can be in one of several states. This enum is returned as the
470+
/// Err() type describing which state the payment is in, see the description of individual enum
471+
/// states for more.
472+
#[derive(Debug)]
473+
pub enum PaymentSendFailure {
474+
/// A parameter which was passed to send_payment was invalid, preventing us from attempting to
475+
/// send the payment at all. No channel state has been changed or messages sent to peers, and
476+
/// once you've changed the parameter at error, you can freely retry the payment in full.
477+
ParameterError(APIError),
478+
/// All paths which were attempted failed to send, with no channel state change taking place.
479+
/// You can freely retry the payment in full (though you probably want to do so over different
480+
/// paths than the ones selected).
481+
AllFailedRetrySafe(Vec<APIError>),
482+
/// Some paths which were attempted failed to send, though possibly not all. At least some
483+
/// paths have irrevocably committed to the HTLC and retrying the payment in full would result
484+
/// in over-/re-payment.
485+
///
486+
/// The results here are ordered the same as the paths in the route object which was passed to
487+
/// send_payment, and any Errs which are not APIError::MonitorUpdateFailed can be safely
488+
/// retried.
489+
///
490+
/// Any entries which contain Err(APIError::MonitorUpdateFailed) or Ok(()) MUST NOT be retried
491+
/// as they will result in over-/re-payment.
492+
PartialFailure(Vec<Result<(), APIError>>),
493+
}
494+
478495
macro_rules! handle_error {
479496
($self: ident, $internal: expr, $their_node_id: expr, $locked_channel_state: expr) => {
480497
match $internal {
@@ -1169,109 +1186,154 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
11691186
/// payment_preimage tracking (which you should already be doing as they represent "proof of
11701187
/// payment") and prevent double-sends yourself.
11711188
///
1172-
/// May generate a SendHTLCs message event on success, which should be relayed.
1189+
/// May generate SendHTLCs message(s) event on success, which should be relayed.
1190+
///
1191+
/// Each path may have a different return value, and PaymentSendValue may return a Vec with
1192+
/// each entry matching the corresponding-index entry in the route paths.
11731193
///
1174-
/// Raises APIError::RoutError when invalid route or forward parameter
1175-
/// (cltv_delta, fee, node public key) is specified.
1176-
/// Raises APIError::ChannelUnavailable if the next-hop channel is not available for updates
1177-
/// (including due to previous monitor update failure or new permanent monitor update failure).
1178-
/// Raised APIError::MonitorUpdateFailed if a new monitor update failure prevented sending the
1179-
/// relevant updates.
1194+
/// In general, a path may raise:
1195+
/// * APIError::RouteError when an invalid route or forwarding parameter (cltv_delta, fee,
1196+
/// node public key) is specified.
1197+
/// * APIError::ChannelUnavailable if the next-hop channel is not available for updates
1198+
/// (including due to previous monitor update failure or new permanent monitor update
1199+
/// failure).
1200+
/// * APIError::MonitorUpdateFailed if a new monitor update failure prevented sending the
1201+
/// relevant updates.
11801202
///
1181-
/// In case of APIError::RouteError/APIError::ChannelUnavailable, the payment send has failed
1182-
/// and you may wish to retry via a different route immediately.
1183-
/// In case of APIError::MonitorUpdateFailed, the commitment update has been irrevocably
1184-
/// committed on our end and we're just waiting for a monitor update to send it. Do NOT retry
1185-
/// the payment via a different route unless you intend to pay twice!
1203+
/// Note that depending on the type of the PaymentSendFailure the HTLC may have been
1204+
/// irrevocably committed to on our end. In such a case, do NOT retry the payment with a
1205+
/// different route unless you intend to pay twice!
11861206
///
11871207
/// payment_secret is unrelated to payment_hash (or PaymentPreimage) and exists to authenticate
11881208
/// the sender to the recipient and prevent payment-probing (deanonymization) attacks. For
11891209
/// newer nodes, it will be provided to you in the invoice. If you do not have one, the Route
11901210
/// must not contain multiple paths as otherwise the multipath data cannot be sent.
11911211
/// If a payment_secret *is* provided, we assume that the invoice had the basic_mpp feature bit
11921212
/// set (either as required or as available).
1193-
pub fn send_payment(&self, route: Route, payment_hash: PaymentHash, payment_secret: Option<&[u8; 32]>) -> Result<(), APIError> {
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"});
1213+
pub fn send_payment(&self, route: Route, payment_hash: PaymentHash, payment_secret: Option<&[u8; 32]>) -> Result<(), PaymentSendFailure> {
1214+
if route.paths.len() < 1 {
1215+
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "There must be at least one path to send over"}));
11961216
}
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"});
1217+
if route.paths.len() > 10 {
1218+
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "Sending over more than 10 paths is not currently supported"}));
11991219
}
1220+
let mut total_value = 0;
12001221
let our_node_id = self.get_our_node_id();
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"});
1222+
for path in route.paths.iter() {
1223+
if path.len() < 1 || path.len() > 20 {
1224+
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "Path didn't go anywhere/had bogus size"}));
1225+
}
1226+
for (idx, hop) in path.iter().enumerate() {
1227+
if idx != path.len() - 1 && hop.pubkey == our_node_id {
1228+
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "Path went through us but wasn't a simple rebalance loop to us"}));
1229+
}
12041230
}
1231+
total_value += path.last().unwrap().fee_msat;
12051232
}
1206-
1207-
let (session_priv, prng_seed) = self.keys_manager.get_onion_rand();
1208-
12091233
let cur_height = self.latest_block_height.load(Ordering::Acquire) as u32 + 1;
1234+
let mut results = Vec::new();
1235+
'path_loop: for path in route.paths.iter() {
1236+
macro_rules! check_res_push {
1237+
($res: expr) => { match $res {
1238+
Ok(r) => r,
1239+
Err(e) => {
1240+
results.push(Err(e));
1241+
continue 'path_loop;
1242+
},
1243+
}
1244+
}
1245+
}
12101246

1211-
let onion_keys = secp_call!(onion_utils::construct_onion_keys(&self.secp_ctx, &route.paths[0], &session_priv),
1212-
APIError::RouteError{err: "Pubkey along hop was maliciously selected"});
1213-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], payment_secret, cur_height)?;
1214-
if onion_utils::route_size_insane(&onion_payloads) {
1215-
return Err(APIError::RouteError{err: "Route size too large considering onion data"});
1216-
}
1217-
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, &payment_hash);
1247+
log_trace!(self, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id);
1248+
let (session_priv, prng_seed) = self.keys_manager.get_onion_rand();
12181249

1219-
let _ = self.total_consistency_lock.read().unwrap();
1250+
let onion_keys = check_res_push!(onion_utils::construct_onion_keys(&self.secp_ctx, &path, &session_priv)
1251+
.map_err(|_| APIError::RouteError{err: "Pubkey along hop was maliciously selected"}));
1252+
let (onion_payloads, htlc_msat, htlc_cltv) = check_res_push!(onion_utils::build_onion_payloads(&path, total_value, payment_secret, cur_height));
1253+
if onion_utils::route_size_insane(&onion_payloads) {
1254+
check_res_push!(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);
12201257

1221-
let mut channel_lock = self.channel_state.lock().unwrap();
1222-
let err: Result<(), _> = loop {
1258+
let _ = self.total_consistency_lock.read().unwrap();
12231259

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

1229-
let channel_state = &mut *channel_lock;
1230-
if let hash_map::Entry::Occupied(mut chan) = channel_state.by_id.entry(id) {
1231-
match {
1232-
if chan.get().get_their_node_id() != route.paths[0].first().unwrap().pubkey {
1233-
return Err(APIError::RouteError{err: "Node ID mismatch on first hop!"});
1234-
}
1235-
if !chan.get().is_live() {
1236-
return Err(APIError::ChannelUnavailable{err: "Peer for first hop currently disconnected/pending monitor update!"});
1237-
}
1238-
break_chan_entry!(self, chan.get_mut().send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute {
1239-
path: route.paths[0].clone(),
1240-
session_priv: session_priv.clone(),
1241-
first_hop_htlc_msat: htlc_msat,
1242-
}, onion_packet), channel_state, chan)
1243-
} {
1244-
Some((update_add, commitment_signed, chan_monitor)) => {
1245-
if let Err(e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) {
1246-
maybe_break_monitor_err!(self, e, channel_state, chan, RAACommitmentOrder::CommitmentFirst, false, true);
1247-
// Note that MonitorUpdateFailed here indicates (per function docs)
1248-
// that we will resent the commitment update once we unfree monitor
1249-
// updating, so we have to take special care that we don't return
1250-
// something else in case we will resend later!
1251-
return Err(APIError::MonitorUpdateFailed);
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() != path.first().unwrap().pubkey {
1271+
check_res_push!(Err(APIError::RouteError{err: "Node ID mismatch on first hop!"}));
12521272
}
1273+
if !chan.get().is_live() {
1274+
check_res_push!(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: path.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, chan_monitor)) => {
1283+
if let Err(e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) {
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+
check_res_push!(Err(APIError::MonitorUpdateFailed));
1290+
}
12531291

1254-
channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
1255-
node_id: route.paths[0].first().unwrap().pubkey,
1256-
updates: msgs::CommitmentUpdate {
1257-
update_add_htlcs: vec![update_add],
1258-
update_fulfill_htlcs: Vec::new(),
1259-
update_fail_htlcs: Vec::new(),
1260-
update_fail_malformed_htlcs: Vec::new(),
1261-
update_fee: None,
1262-
commitment_signed,
1263-
},
1264-
});
1265-
},
1266-
None => {},
1267-
}
1268-
} else { unreachable!(); }
1269-
return Ok(());
1270-
};
1292+
channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
1293+
node_id: path.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+
results.push(Ok(()));
1308+
continue 'path_loop;
1309+
};
12711310

1272-
match handle_error!(self, err, route.paths[0].first().unwrap().pubkey, channel_lock) {
1273-
Ok(_) => unreachable!(),
1274-
Err(e) => { Err(APIError::ChannelUnavailable { err: e.err }) }
1311+
match handle_error!(self, err, path.first().unwrap().pubkey, channel_lock) {
1312+
Ok(_) => unreachable!(),
1313+
Err(e) => {
1314+
check_res_push!(Err(APIError::ChannelUnavailable { err: e.err }));
1315+
},
1316+
}
1317+
}
1318+
let mut has_ok = false;
1319+
let mut has_err = false;
1320+
for res in results.iter() {
1321+
if res.is_ok() { has_ok = true; }
1322+
if res.is_err() { has_err = true; }
1323+
if let &Err(APIError::MonitorUpdateFailed) = res {
1324+
// MonitorUpdateFailed is inherently unsafe to retry, so we call it a
1325+
// PartialFailure.
1326+
has_err = true;
1327+
has_ok = true;
1328+
break;
1329+
}
1330+
}
1331+
if has_err && has_ok {
1332+
Err(PaymentSendFailure::PartialFailure(results))
1333+
} else if has_err {
1334+
Err(PaymentSendFailure::AllFailedRetrySafe(results.drain(..).map(|r| r.unwrap_err()).collect()))
1335+
} else {
1336+
Ok(())
12751337
}
12761338
}
12771339

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,RAACommitmentOrder, PaymentPreimage, PaymentHash};
7+
use ln::channelmanager::{ChannelManager,RAACommitmentOrder, PaymentPreimage, PaymentHash, PaymentSendFailure};
88
use ln::router::{Route, Router};
99
use ln::features::InitFeatures;
1010
use ln::msgs;
@@ -171,6 +171,28 @@ macro_rules! get_feerate {
171171
}
172172
}
173173

174+
macro_rules! unwrap_send_err {
175+
($res: expr, $all_failed: expr, $type: pat, $check: expr) => {
176+
match &$res {
177+
&Err(PaymentSendFailure::AllFailedRetrySafe(ref fails)) if $all_failed => {
178+
assert_eq!(fails.len(), 1);
179+
match fails[0] {
180+
$type => { $check },
181+
_ => panic!(),
182+
}
183+
},
184+
&Err(PaymentSendFailure::PartialFailure(ref fails)) if !$all_failed => {
185+
assert_eq!(fails.len(), 1);
186+
match fails[0] {
187+
Err($type) => { $check },
188+
_ => panic!(),
189+
}
190+
},
191+
_ => panic!(),
192+
}
193+
}
194+
}
195+
174196
pub fn create_funding_transaction<'a, 'b>(node: &Node<'a, 'b>, expected_chan_value: u64, expected_user_chan_id: u64) -> ([u8; 32], Transaction, OutPoint) {
175197
let chan_id = *node.network_chan_count.borrow();
176198

@@ -798,12 +820,8 @@ pub fn route_over_limit<'a, 'b>(origin_node: &Node<'a, 'b>, expected_route: &[&N
798820
}
799821

800822
let (_, our_payment_hash) = get_payment_preimage_hash!(origin_node);
801-
802-
let err = origin_node.node.send_payment(route, our_payment_hash, None).err().unwrap();
803-
match err {
804-
APIError::ChannelUnavailable{err} => assert_eq!(err, "Cannot send value that would put us over the max HTLC value in flight our peer will accept"),
805-
_ => panic!("Unknown error variants"),
806-
};
823+
unwrap_send_err!(origin_node.node.send_payment(route, our_payment_hash, None), true, APIError::ChannelUnavailable { err },
824+
assert_eq!(err, "Cannot send value that would put us over the max HTLC value in flight our peer will accept"));
807825
}
808826

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

0 commit comments

Comments
 (0)