Skip to content

Commit 6bbafa5

Browse files
committed
Support (de)serializing payment_data in onion TLVs and track them
This is the first step in Base AMP support, just tracking the relevant data in internal datastructures.
1 parent 1652f33 commit 6bbafa5

File tree

3 files changed

+86
-35
lines changed

3 files changed

+86
-35
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ enum PendingForwardReceiveHTLCInfo {
7474
onion_packet: msgs::OnionPacket,
7575
short_channel_id: u64, // This should be NonZero<u64> eventually
7676
},
77-
Receive {},
77+
Receive {
78+
payment_data: Option<msgs::FinalOnionHopData>,
79+
},
7880
}
7981

8082
#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
@@ -119,6 +121,12 @@ pub(super) struct HTLCPreviousHopData {
119121
incoming_packet_shared_secret: [u8; 32],
120122
}
121123

124+
struct ClaimableHTLC {
125+
src: HTLCPreviousHopData,
126+
value: u64,
127+
payment_data: Option<msgs::FinalOnionHopData>,
128+
}
129+
122130
/// Tracks the inbound corresponding to an outbound HTLC
123131
#[derive(Clone, PartialEq)]
124132
pub(super) enum HTLCSource {
@@ -276,12 +284,11 @@ pub(super) struct ChannelHolder<ChanSigner: ChannelKeys> {
276284
/// guarantees are made about the existence of a channel with the short id here, nor the short
277285
/// ids in the PendingHTLCInfo!
278286
pub(super) forward_htlcs: HashMap<u64, Vec<HTLCForwardInfo>>,
279-
/// payment_hash -> Vec<(amount_received, htlc_source)> for tracking things that were to us and
280-
/// can be failed/claimed by the user
287+
/// Tracks things that were to us and can be failed/claimed by the user
281288
/// Note that while this is held in the same mutex as the channels themselves, no consistency
282289
/// guarantees are made about the channels given here actually existing anymore by the time you
283290
/// go to read them!
284-
pub(super) claimable_htlcs: HashMap<PaymentHash, Vec<(u64, HTLCPreviousHopData)>>,
291+
claimable_htlcs: HashMap<PaymentHash, Vec<ClaimableHTLC>>,
285292
/// Messages to send to peers - pushed to in the same lock that they are generated in (except
286293
/// for broadcast messages, where ordering isn't as strict).
287294
pub(super) pending_msg_events: Vec<events::MessageSendEvent>,
@@ -976,13 +983,19 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
976983
return_err!("Upstream node set CLTV to the wrong value", 18, &byte_utils::be32_to_array(msg.cltv_expiry));
977984
}
978985

986+
let payment_data = match next_hop_data.format {
987+
msgs::OnionHopDataFormat::Legacy { .. } => None,
988+
msgs::OnionHopDataFormat::NonFinalNode { .. } => return_err!("Got non final data with an HMAC of 0", 0x4000 | 22, &[0;0]),
989+
msgs::OnionHopDataFormat::FinalNode { payment_data } => payment_data,
990+
};
991+
979992
// Note that we could obviously respond immediately with an update_fulfill_htlc
980993
// message, however that would leak that we are the recipient of this payment, so
981994
// instead we stay symmetric with the forwarding case, only responding (after a
982995
// delay) once they've send us a commitment_signed!
983996

984997
PendingHTLCStatus::Forward(PendingHTLCInfo {
985-
type_data: PendingForwardReceiveHTLCInfo::Receive {},
998+
type_data: PendingForwardReceiveHTLCInfo::Receive { payment_data },
986999
payment_hash: msg.payment_hash.clone(),
9871000
incoming_shared_secret: shared_secret,
9881001
amt_to_forward: next_hop_data.amt_to_forward,
@@ -1538,17 +1551,18 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
15381551
for forward_info in pending_forwards.drain(..) {
15391552
match forward_info {
15401553
HTLCForwardInfo::AddHTLC { prev_short_channel_id, prev_htlc_id, forward_info: PendingHTLCInfo {
1541-
type_data: PendingForwardReceiveHTLCInfo::Receive { },
1554+
type_data: PendingForwardReceiveHTLCInfo::Receive { payment_data },
15421555
incoming_shared_secret, payment_hash, amt_to_forward, .. }, } => {
15431556
let prev_hop_data = HTLCPreviousHopData {
15441557
short_channel_id: prev_short_channel_id,
15451558
htlc_id: prev_htlc_id,
15461559
incoming_packet_shared_secret: incoming_shared_secret,
15471560
};
1548-
match channel_state.claimable_htlcs.entry(payment_hash) {
1549-
hash_map::Entry::Occupied(mut entry) => entry.get_mut().push((amt_to_forward, prev_hop_data)),
1550-
hash_map::Entry::Vacant(entry) => { entry.insert(vec![(amt_to_forward, prev_hop_data)]); },
1551-
};
1561+
channel_state.claimable_htlcs.entry(payment_hash).or_insert(Vec::new()).push(ClaimableHTLC {
1562+
src: prev_hop_data,
1563+
value: amt_to_forward,
1564+
payment_data,
1565+
});
15521566
new_events.push(events::Event::PaymentReceived {
15531567
payment_hash: payment_hash,
15541568
amt: amt_to_forward,
@@ -1621,11 +1635,11 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
16211635
let mut channel_state = Some(self.channel_state.lock().unwrap());
16221636
let removed_source = channel_state.as_mut().unwrap().claimable_htlcs.remove(payment_hash);
16231637
if let Some(mut sources) = removed_source {
1624-
for (recvd_value, htlc_with_hash) in sources.drain(..) {
1638+
for htlc in sources.drain(..) {
16251639
if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); }
16261640
self.fail_htlc_backwards_internal(channel_state.take().unwrap(),
1627-
HTLCSource::PreviousHopData(htlc_with_hash), payment_hash,
1628-
HTLCFailReason::Reason { failure_code: 0x4000 | 15, data: byte_utils::be64_to_array(recvd_value).to_vec() });
1641+
HTLCSource::PreviousHopData(htlc.src), payment_hash,
1642+
HTLCFailReason::Reason { failure_code: 0x4000 | 15, data: byte_utils::be64_to_array(htlc.value).to_vec() });
16291643
}
16301644
true
16311645
} else { false }
@@ -1749,17 +1763,17 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
17491763
let mut channel_state = Some(self.channel_state.lock().unwrap());
17501764
let removed_source = channel_state.as_mut().unwrap().claimable_htlcs.remove(&payment_hash);
17511765
if let Some(mut sources) = removed_source {
1752-
for (received_amount, htlc_with_hash) in sources.drain(..) {
1766+
for htlc in sources.drain(..) {
17531767
if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); }
1754-
if received_amount < expected_amount || received_amount > expected_amount * 2 {
1755-
let mut htlc_msat_data = byte_utils::be64_to_array(received_amount).to_vec();
1768+
if htlc.value < expected_amount || htlc.value > expected_amount * 2 {
1769+
let mut htlc_msat_data = byte_utils::be64_to_array(htlc.value).to_vec();
17561770
let mut height_data = byte_utils::be32_to_array(self.latest_block_height.load(Ordering::Acquire) as u32).to_vec();
17571771
htlc_msat_data.append(&mut height_data);
17581772
self.fail_htlc_backwards_internal(channel_state.take().unwrap(),
1759-
HTLCSource::PreviousHopData(htlc_with_hash), &payment_hash,
1773+
HTLCSource::PreviousHopData(htlc.src), &payment_hash,
17601774
HTLCFailReason::Reason { failure_code: 0x4000|15, data: htlc_msat_data });
17611775
} else {
1762-
self.claim_funds_internal(channel_state.take().unwrap(), HTLCSource::PreviousHopData(htlc_with_hash), payment_preimage);
1776+
self.claim_funds_internal(channel_state.take().unwrap(), HTLCSource::PreviousHopData(htlc.src), payment_preimage);
17631777
}
17641778
}
17651779
true
@@ -3076,8 +3090,9 @@ impl Writeable for PendingHTLCInfo {
30763090
onion_packet.write(writer)?;
30773091
short_channel_id.write(writer)?;
30783092
},
3079-
&PendingForwardReceiveHTLCInfo::Receive { } => {
3093+
&PendingForwardReceiveHTLCInfo::Receive { ref payment_data } => {
30803094
1u8.write(writer)?;
3095+
payment_data.write(writer)?;
30813096
},
30823097
}
30833098
self.incoming_shared_secret.write(writer)?;
@@ -3096,7 +3111,9 @@ impl<R: ::std::io::Read> Readable<R> for PendingHTLCInfo {
30963111
onion_packet: Readable::read(reader)?,
30973112
short_channel_id: Readable::read(reader)?,
30983113
},
3099-
1u8 => PendingForwardReceiveHTLCInfo::Receive { },
3114+
1u8 => PendingForwardReceiveHTLCInfo::Receive {
3115+
payment_data: Readable::read(reader)?,
3116+
},
31003117
_ => return Err(DecodeError::InvalidValue),
31013118
},
31023119
incoming_shared_secret: Readable::read(reader)?,
@@ -3301,9 +3318,10 @@ impl<ChanSigner: ChannelKeys + Writeable, M: Deref> Writeable for ChannelManager
33013318
for (payment_hash, previous_hops) in channel_state.claimable_htlcs.iter() {
33023319
payment_hash.write(writer)?;
33033320
(previous_hops.len() as u64).write(writer)?;
3304-
for &(recvd_amt, ref previous_hop) in previous_hops.iter() {
3305-
recvd_amt.write(writer)?;
3306-
previous_hop.write(writer)?;
3321+
for htlc in previous_hops.iter() {
3322+
htlc.src.write(writer)?;
3323+
htlc.value.write(writer)?;
3324+
htlc.payment_data.write(writer)?;
33073325
}
33083326
}
33093327

@@ -3445,7 +3463,11 @@ impl<'a, R : ::std::io::Read, ChanSigner: ChannelKeys + Readable<R>, M: Deref> R
34453463
let previous_hops_len: u64 = Readable::read(reader)?;
34463464
let mut previous_hops = Vec::with_capacity(cmp::min(previous_hops_len as usize, 2));
34473465
for _ in 0..previous_hops_len {
3448-
previous_hops.push((Readable::read(reader)?, Readable::read(reader)?));
3466+
previous_hops.push(ClaimableHTLC {
3467+
src: Readable::read(reader)?,
3468+
value: Readable::read(reader)?,
3469+
payment_data: Readable::read(reader)?,
3470+
});
34493471
}
34503472
claimable_htlcs.insert(payment_hash, previous_hops);
34513473
}

lightning/src/ln/msgs.rs

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,11 @@ pub trait RoutingMessageHandler : Send + Sync {
664664
mod fuzzy_internal_msgs {
665665
// These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize
666666
// them from untrusted input):
667+
#[derive(Clone)]
668+
pub(crate) struct FinalOnionHopData {
669+
pub(crate) payment_secret: [u8; 32],
670+
pub(crate) total_msat: u64,
671+
}
667672

668673
pub(crate) enum OnionHopDataFormat {
669674
Legacy { // aka Realm-0
@@ -672,7 +677,9 @@ mod fuzzy_internal_msgs {
672677
NonFinalNode {
673678
short_channel_id: u64,
674679
},
675-
FinalNode,
680+
FinalNode {
681+
payment_data: Option<FinalOnionHopData>,
682+
},
676683
}
677684

678685
pub struct OnionHopData {
@@ -1016,6 +1023,11 @@ impl_writeable!(UpdateAddHTLC, 32+8+8+32+4+1366, {
10161023
onion_routing_packet
10171024
});
10181025

1026+
impl_writeable!(FinalOnionHopData, 32+8, {
1027+
payment_secret,
1028+
total_msat
1029+
});
1030+
10191031
impl Writeable for OnionHopData {
10201032
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
10211033
w.size_hint(33);
@@ -1034,11 +1046,19 @@ impl Writeable for OnionHopData {
10341046
(6, short_channel_id)
10351047
});
10361048
},
1037-
OnionHopDataFormat::FinalNode => {
1038-
encode_varint_length_prefixed_tlv!(w, {
1039-
(2, HighZeroBytesDroppedVarInt(self.amt_to_forward)),
1040-
(4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value))
1041-
});
1049+
OnionHopDataFormat::FinalNode { ref payment_data } => {
1050+
if let &Some(ref final_data) = payment_data {
1051+
encode_varint_length_prefixed_tlv!(w, {
1052+
(2, HighZeroBytesDroppedVarInt(self.amt_to_forward)),
1053+
(4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value)),
1054+
(8, final_data)
1055+
});
1056+
} else {
1057+
encode_varint_length_prefixed_tlv!(w, {
1058+
(2, HighZeroBytesDroppedVarInt(self.amt_to_forward)),
1059+
(4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value))
1060+
});
1061+
}
10421062
},
10431063
}
10441064
Ok(())
@@ -1059,19 +1079,24 @@ impl<R: Read> Readable<R> for OnionHopData {
10591079
let mut amt = HighZeroBytesDroppedVarInt(0u64);
10601080
let mut cltv_value = HighZeroBytesDroppedVarInt(0u32);
10611081
let mut short_id: Option<u64> = None;
1082+
let mut payment_data: Option<FinalOnionHopData> = None;
10621083
decode_tlv!(&mut rd, {
10631084
(2, amt),
10641085
(4, cltv_value)
10651086
}, {
1066-
(6, short_id)
1087+
(6, short_id),
1088+
(8, payment_data)
10671089
});
10681090
rd.eat_remaining().map_err(|_| DecodeError::ShortRead)?;
10691091
let format = if let Some(short_channel_id) = short_id {
1092+
if payment_data.is_some() { return Err(DecodeError::InvalidValue); }
10701093
OnionHopDataFormat::NonFinalNode {
10711094
short_channel_id,
10721095
}
10731096
} else {
1074-
OnionHopDataFormat::FinalNode
1097+
OnionHopDataFormat::FinalNode {
1098+
payment_data
1099+
}
10751100
};
10761101
(format, amt.0, cltv_value.0)
10771102
} else {
@@ -2066,15 +2091,17 @@ mod tests {
20662091
#[test]
20672092
fn encoding_final_onion_hop_data() {
20682093
let mut msg = msgs::OnionHopData {
2069-
format: OnionHopDataFormat::FinalNode,
2094+
format: OnionHopDataFormat::FinalNode {
2095+
payment_data: None,
2096+
},
20702097
amt_to_forward: 0x0badf00d01020304,
20712098
outgoing_cltv_value: 0xffffffff,
20722099
};
20732100
let encoded_value = msg.encode();
20742101
let target_value = hex::decode("1002080badf00d010203040404ffffffff").unwrap();
20752102
assert_eq!(encoded_value, target_value);
20762103
msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
2077-
if let OnionHopDataFormat::FinalNode = msg.format { } else { panic!(); }
2104+
if let OnionHopDataFormat::FinalNode { payment_data: None } = msg.format { } else { panic!(); }
20782105
assert_eq!(msg.amt_to_forward, 0x0badf00d01020304);
20792106
assert_eq!(msg.outgoing_cltv_value, 0xffffffff);
20802107
}

lightning/src/ln/onion_utils.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,9 @@ pub(super) fn build_onion_payloads(route: &Route, starting_htlc_offset: u32) ->
123123
res.insert(0, msgs::OnionHopData {
124124
format: if hop.node_features.supports_variable_length_onion() {
125125
if idx == 0 {
126-
msgs::OnionHopDataFormat::FinalNode
126+
msgs::OnionHopDataFormat::FinalNode {
127+
payment_data: None,
128+
}
127129
} else {
128130
msgs::OnionHopDataFormat::NonFinalNode {
129131
short_channel_id: last_short_channel_id,

0 commit comments

Comments
 (0)