Skip to content

Commit c986e52

Browse files
Add MppId field to HTLCSource as a way to correlate mpp payment paths
1 parent f6f950d commit c986e52

File tree

4 files changed

+86
-17
lines changed

4 files changed

+86
-17
lines changed

lightning/src/ln/channel.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5525,7 +5525,7 @@ mod tests {
55255525
use bitcoin::hashes::hex::FromHex;
55265526
use hex;
55275527
use ln::{PaymentPreimage, PaymentHash};
5528-
use ln::channelmanager::HTLCSource;
5528+
use ln::channelmanager::{HTLCSource, MppId};
55295529
use ln::channel::{Channel,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,HTLCCandidate,HTLCInitiator,TxCreationKeys};
55305530
use ln::channel::MAX_FUNDING_SATOSHIS;
55315531
use ln::features::InitFeatures;
@@ -5699,6 +5699,7 @@ mod tests {
56995699
path: Vec::new(),
57005700
session_priv: SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
57015701
first_hop_htlc_msat: 548,
5702+
mpp_id: MppId([42; 32]),
57025703
}
57035704
});
57045705

lightning/src/ln/channelmanager.rs

Lines changed: 80 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,22 @@ struct ClaimableHTLC {
173173
onion_payload: OnionPayload,
174174
}
175175

176+
/// A payment identifier used to correlate an MPP payment's per-path HTLC sources internally.
177+
#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)]
178+
pub(crate) struct MppId(pub [u8; 32]);
179+
180+
impl Writeable for MppId {
181+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
182+
self.0.write(w)
183+
}
184+
}
185+
186+
impl Readable for MppId {
187+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
188+
let buf: [u8; 32] = Readable::read(r)?;
189+
Ok(MppId(buf))
190+
}
191+
}
176192
/// Tracks the inbound corresponding to an outbound HTLC
177193
#[derive(Clone, PartialEq)]
178194
pub(crate) enum HTLCSource {
@@ -183,6 +199,7 @@ pub(crate) enum HTLCSource {
183199
/// Technically we can recalculate this from the route, but we cache it here to avoid
184200
/// doing a double-pass on route when we get a failure back
185201
first_hop_htlc_msat: u64,
202+
mpp_id: MppId,
186203
},
187204
}
188205
#[cfg(test)]
@@ -192,6 +209,7 @@ impl HTLCSource {
192209
path: Vec::new(),
193210
session_priv: SecretKey::from_slice(&[1; 32]).unwrap(),
194211
first_hop_htlc_msat: 0,
212+
mpp_id: MppId([2; 32]),
195213
}
196214
}
197215
}
@@ -1820,7 +1838,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
18201838
}
18211839

18221840
// Only public for testing, this should otherwise never be called direcly
1823-
pub(crate) fn send_payment_along_path(&self, path: &Vec<RouteHop>, payment_hash: &PaymentHash, payment_secret: &Option<PaymentSecret>, total_value: u64, cur_height: u32, keysend_preimage: &Option<PaymentPreimage>) -> Result<(), APIError> {
1841+
pub(crate) fn send_payment_along_path(&self, path: &Vec<RouteHop>, payment_hash: &PaymentHash, payment_secret: &Option<PaymentSecret>, total_value: u64, cur_height: u32, mpp_id: MppId, keysend_preimage: &Option<PaymentPreimage>) -> Result<(), APIError> {
18241842
log_trace!(self.logger, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id);
18251843
let prng_seed = self.keys_manager.get_secure_random_bytes();
18261844
let session_priv_bytes = self.keys_manager.get_secure_random_bytes();
@@ -1857,6 +1875,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
18571875
path: path.clone(),
18581876
session_priv: session_priv.clone(),
18591877
first_hop_htlc_msat: htlc_msat,
1878+
mpp_id,
18601879
}, onion_packet, &self.logger), channel_state, chan)
18611880
} {
18621881
Some((update_add, commitment_signed, monitor_update)) => {
@@ -1956,6 +1975,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
19561975
let mut total_value = 0;
19571976
let our_node_id = self.get_our_node_id();
19581977
let mut path_errs = Vec::with_capacity(route.paths.len());
1978+
let mpp_id = MppId(self.keys_manager.get_secure_random_bytes());
19591979
'path_check: for path in route.paths.iter() {
19601980
if path.len() < 1 || path.len() > 20 {
19611981
path_errs.push(Err(APIError::RouteError{err: "Path didn't go anywhere/had bogus size"}));
@@ -1977,7 +1997,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
19771997
let cur_height = self.best_block.read().unwrap().height() + 1;
19781998
let mut results = Vec::new();
19791999
for path in route.paths.iter() {
1980-
results.push(self.send_payment_along_path(&path, &payment_hash, payment_secret, total_value, cur_height, &keysend_preimage));
2000+
results.push(self.send_payment_along_path(&path, &payment_hash, payment_secret, total_value, cur_height, mpp_id, &keysend_preimage));
19812001
}
19822002
let mut has_ok = false;
19832003
let mut has_err = false;
@@ -4911,14 +4931,60 @@ impl Readable for ClaimableHTLC {
49114931
}
49124932
}
49134933

4914-
impl_writeable_tlv_based_enum!(HTLCSource,
4915-
(0, OutboundRoute) => {
4916-
(0, session_priv, required),
4917-
(2, first_hop_htlc_msat, required),
4918-
(4, path, vec_type),
4919-
}, ;
4920-
(1, PreviousHopData)
4921-
);
4934+
impl Readable for HTLCSource {
4935+
fn read<R: Read>(reader: &mut R) -> Result<Self, DecodeError> {
4936+
let id: u8 = Readable::read(reader)?;
4937+
match id {
4938+
0 => {
4939+
let mut session_priv: ::util::ser::OptionDeserWrapper<SecretKey> = ::util::ser::OptionDeserWrapper(None);
4940+
let mut first_hop_htlc_msat: u64 = 0;
4941+
let mut path = Some(Vec::new());
4942+
let mut mpp_id = None;
4943+
read_tlv_fields!(reader, {
4944+
(0, session_priv, required),
4945+
(1, mpp_id, option),
4946+
(2, first_hop_htlc_msat, required),
4947+
(4, path, vec_type),
4948+
});
4949+
if mpp_id.is_none() {
4950+
// For backwards compat, if there was no mpp_id written, use the session_priv bytes
4951+
// instead.
4952+
mpp_id = Some(MppId(*session_priv.0.unwrap().as_ref()));
4953+
}
4954+
Ok(HTLCSource::OutboundRoute {
4955+
session_priv: session_priv.0.unwrap(),
4956+
first_hop_htlc_msat: first_hop_htlc_msat,
4957+
path: path.unwrap(),
4958+
mpp_id: mpp_id.unwrap(),
4959+
})
4960+
}
4961+
1 => Ok(HTLCSource::PreviousHopData(Readable::read(reader)?)),
4962+
_ => Err(DecodeError::UnknownRequiredFeature),
4963+
}
4964+
}
4965+
}
4966+
4967+
impl Writeable for HTLCSource {
4968+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::io::Error> {
4969+
match self {
4970+
HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, mpp_id } => {
4971+
0u8.write(writer)?;
4972+
let mpp_id_opt = Some(mpp_id);
4973+
write_tlv_fields!(writer, {
4974+
(0, session_priv, required),
4975+
(1, mpp_id_opt, option),
4976+
(2, first_hop_htlc_msat, required),
4977+
(4, path, vec_type),
4978+
});
4979+
}
4980+
HTLCSource::PreviousHopData(ref field) => {
4981+
1u8.write(writer)?;
4982+
field.write(writer)?;
4983+
}
4984+
}
4985+
Ok(())
4986+
}
4987+
}
49224988

49234989
impl_writeable_tlv_based_enum!(HTLCFailReason,
49244990
(0, LightningError) => {
@@ -5364,7 +5430,7 @@ mod tests {
53645430
use bitcoin::hashes::sha256::Hash as Sha256;
53655431
use core::time::Duration;
53665432
use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
5367-
use ln::channelmanager::PaymentSendFailure;
5433+
use ln::channelmanager::{MppId, PaymentSendFailure};
53685434
use ln::features::{InitFeatures, InvoiceFeatures};
53695435
use ln::functional_test_utils::*;
53705436
use ln::msgs;
@@ -5515,10 +5581,11 @@ mod tests {
55155581
let net_graph_msg_handler = &nodes[0].net_graph_msg_handler;
55165582
let route = get_route(&nodes[0].node.get_our_node_id(), &net_graph_msg_handler.network_graph, &nodes[1].node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &Vec::new(), 100_000, TEST_FINAL_CLTV, &logger).unwrap();
55175583
let (payment_preimage, our_payment_hash, payment_secret) = get_payment_preimage_hash!(&nodes[1]);
5584+
let mpp_id = MppId([42; 32]);
55185585
// Use the utility function send_payment_along_path to send the payment with MPP data which
55195586
// indicates there are more HTLCs coming.
55205587
let cur_height = CHAN_CONFIRM_DEPTH + 1; // route_payment calls send_payment, which adds 1 to the current height. So we do the same here to match.
5521-
nodes[0].node.send_payment_along_path(&route.paths[0], &our_payment_hash, &Some(payment_secret), 200_000, cur_height, &None).unwrap();
5588+
nodes[0].node.send_payment_along_path(&route.paths[0], &our_payment_hash, &Some(payment_secret), 200_000, cur_height, mpp_id, &None).unwrap();
55225589
check_added_monitors!(nodes[0], 1);
55235590
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
55245591
assert_eq!(events.len(), 1);
@@ -5548,7 +5615,7 @@ mod tests {
55485615
expect_payment_failed!(nodes[0], our_payment_hash, true);
55495616

55505617
// Send the second half of the original MPP payment.
5551-
nodes[0].node.send_payment_along_path(&route.paths[0], &our_payment_hash, &Some(payment_secret), 200_000, cur_height, &None).unwrap();
5618+
nodes[0].node.send_payment_along_path(&route.paths[0], &our_payment_hash, &Some(payment_secret), 200_000, cur_height, mpp_id, &None).unwrap();
55525619
check_added_monitors!(nodes[0], 1);
55535620
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
55545621
assert_eq!(events.len(), 1);

lightning/src/ln/functional_tests.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use chain::transaction::OutPoint;
1919
use chain::keysinterface::BaseSign;
2020
use ln::{PaymentPreimage, PaymentSecret, PaymentHash};
2121
use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC};
22-
use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA};
22+
use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, MppId, RAACommitmentOrder, PaymentSendFailure, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA};
2323
use ln::channel::{Channel, ChannelError};
2424
use ln::{chan_utils, onion_utils};
2525
use ln::chan_utils::HTLC_SUCCESS_TX_WEIGHT;
@@ -3886,7 +3886,8 @@ fn do_test_htlc_timeout(send_partial_mpp: bool) {
38863886
// Use the utility function send_payment_along_path to send the payment with MPP data which
38873887
// indicates there are more HTLCs coming.
38883888
let cur_height = CHAN_CONFIRM_DEPTH + 1; // route_payment calls send_payment, which adds 1 to the current height. So we do the same here to match.
3889-
nodes[0].node.send_payment_along_path(&route.paths[0], &our_payment_hash, &Some(payment_secret), 200000, cur_height, &None).unwrap();
3889+
let mpp_id = MppId([42; 32]);
3890+
nodes[0].node.send_payment_along_path(&route.paths[0], &our_payment_hash, &Some(payment_secret), 200000, cur_height, mpp_id, &None).unwrap();
38903891
check_added_monitors!(nodes[0], 1);
38913892
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
38923893
assert_eq!(events.len(), 1);

lightning/src/ln/onion_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ pub(super) fn build_first_hop_failure_packet(shared_secret: &[u8], failure_type:
332332
/// Returns update, a boolean indicating that the payment itself failed, and the error code.
333333
#[inline]
334334
pub(super) fn process_onion_failure<T: secp256k1::Signing, L: Deref>(secp_ctx: &Secp256k1<T>, logger: &L, htlc_source: &HTLCSource, mut packet_decrypted: Vec<u8>) -> (Option<NetworkUpdate>, bool, Option<u16>, Option<Vec<u8>>) where L::Target: Logger {
335-
if let &HTLCSource::OutboundRoute { ref path, ref session_priv, ref first_hop_htlc_msat } = htlc_source {
335+
if let &HTLCSource::OutboundRoute { ref path, ref session_priv, ref first_hop_htlc_msat, .. } = htlc_source {
336336
let mut res = None;
337337
let mut htlc_msat = *first_hop_htlc_msat;
338338
let mut error_code_ret = None;

0 commit comments

Comments
 (0)