Skip to content

Commit c3d8aa3

Browse files
Test failing phantom payments
Also fix a bug where we were failing back phantom payments with the wrong scid, causing them to never actually be failed backwards.
1 parent 8e7f241 commit c3d8aa3

File tree

3 files changed

+319
-42
lines changed

3 files changed

+319
-42
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ mod inbound_payment {
358358
// our payment, which we can use to decode errors or inform the user that the payment was sent.
359359

360360
#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
361-
enum PendingHTLCRouting {
361+
pub(super) enum PendingHTLCRouting {
362362
Forward {
363363
onion_packet: msgs::OnionPacket,
364364
short_channel_id: u64, // This should be NonZero<u64> eventually when we bump MSRV
@@ -375,8 +375,8 @@ enum PendingHTLCRouting {
375375

376376
#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
377377
pub(super) struct PendingHTLCInfo {
378-
routing: PendingHTLCRouting,
379-
incoming_shared_secret: [u8; 32],
378+
pub(super) routing: PendingHTLCRouting,
379+
pub(super) incoming_shared_secret: [u8; 32],
380380
payment_hash: PaymentHash,
381381
pub(super) amt_to_forward: u64,
382382
pub(super) outgoing_cltv_value: u32,
@@ -3011,45 +3011,62 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
30113011
HTLCForwardInfo::AddHTLC { prev_short_channel_id, prev_htlc_id, forward_info: PendingHTLCInfo {
30123012
routing, incoming_shared_secret, payment_hash, amt_to_forward, outgoing_cltv_value },
30133013
prev_funding_outpoint } => {
3014+
macro_rules! get_failure_htlc_source {
3015+
() => {
3016+
HTLCSource::PreviousHopData(HTLCPreviousHopData {
3017+
short_channel_id: prev_short_channel_id,
3018+
outpoint: prev_funding_outpoint,
3019+
htlc_id: prev_htlc_id,
3020+
incoming_packet_shared_secret: incoming_shared_secret,
3021+
})
3022+
}
3023+
}
30143024
macro_rules! fail_forward {
30153025
($msg: expr, $err_code: expr, $err_data: expr) => {
30163026
{
30173027
log_info!(self.logger, "Failed to accept/forward incoming HTLC: {}", $msg);
3018-
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
3019-
short_channel_id: short_chan_id,
3020-
outpoint: prev_funding_outpoint,
3021-
htlc_id: prev_htlc_id,
3022-
incoming_packet_shared_secret: incoming_shared_secret,
3023-
});
3024-
failed_forwards.push((htlc_source, payment_hash,
3028+
failed_forwards.push((get_failure_htlc_source!(), payment_hash,
30253029
HTLCFailReason::Reason { failure_code: $err_code, data: $err_data }
30263030
));
30273031
continue;
30283032
}
30293033
}
30303034
}
3035+
macro_rules! fail_phantom_forward {
3036+
($msg: expr, $err_code: expr, $err_data: expr, $phantom_shared_secret: expr) => {
3037+
{
3038+
log_info!(self.logger, "Failed to accept/forward incoming phantom node HTLC: {}", $msg);
3039+
let packet = onion_utils::build_failure_packet(&$phantom_shared_secret, $err_code, &$err_data[..]).encode();
3040+
let error_data = onion_utils::encrypt_failure_packet(&$phantom_shared_secret, &packet);
3041+
failed_forwards.push((get_failure_htlc_source!(), payment_hash,
3042+
HTLCFailReason::LightningError { err: error_data }
3043+
));
3044+
continue;
3045+
}
3046+
}
3047+
}
30313048
if let PendingHTLCRouting::Forward { onion_packet, .. } = routing {
30323049
let phantom_secret_res = self.keys_manager.get_node_secret(Recipient::PhantomNode);
30333050
if phantom_secret_res.is_ok() && fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, short_chan_id) {
3034-
let shared_secret = {
3051+
let phantom_shared_secret = {
30353052
let mut arr = [0; 32];
30363053
arr.copy_from_slice(&SharedSecret::new(&onion_packet.public_key.unwrap(), &phantom_secret_res.unwrap())[..]);
30373054
arr
30383055
};
3039-
let next_hop = match onion_utils::decode_next_hop(shared_secret, &onion_packet.hop_data, onion_packet.hmac, payment_hash) {
3056+
let next_hop = match onion_utils::decode_next_hop(phantom_shared_secret, &onion_packet.hop_data, onion_packet.hmac, payment_hash) {
30403057
Ok(res) => res,
30413058
Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {
3042-
fail_forward!(err_msg, err_code, Vec::new());
3059+
fail_phantom_forward!(err_msg, err_code, Vec::new(), phantom_shared_secret);
30433060
},
30443061
Err(onion_utils::OnionDecodeErr::Relay { err_msg, err_code }) => {
3045-
fail_forward!(err_msg, err_code, Vec::new());
3062+
fail_phantom_forward!(err_msg, err_code, Vec::new(), phantom_shared_secret);
30463063
},
30473064
};
30483065
match next_hop {
30493066
onion_utils::Hop::Receive(hop_data) => {
3050-
match self.construct_recv_pending_htlc_info(hop_data, shared_secret, payment_hash, amt_to_forward, outgoing_cltv_value) {
3067+
match self.construct_recv_pending_htlc_info(hop_data, phantom_shared_secret, payment_hash, amt_to_forward, outgoing_cltv_value) {
30513068
Ok(info) => phantom_receives.push((prev_short_channel_id, prev_funding_outpoint, vec![(info, prev_htlc_id)])),
3052-
Err(ReceiveError { err_code, err_data, msg }) => fail_forward!(msg, err_code, err_data)
3069+
Err(ReceiveError { err_code, err_data, msg }) => fail_phantom_forward!(msg, err_code, err_data, phantom_shared_secret)
30533070
}
30543071
},
30553072
_ => panic!(),

lightning/src/ln/msgs.rs

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,39 +1289,58 @@ impl Readable for FinalOnionHopData {
12891289
}
12901290
}
12911291

1292-
impl Writeable for OnionHopData {
1293-
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
1294-
// Note that this should never be reachable if Rust-Lightning generated the message, as we
1295-
// check values are sane long before we get here, though its possible in the future
1296-
// user-generated messages may hit this.
1297-
if self.amt_to_forward > MAX_VALUE_MSAT { panic!("We should never be sending infinite/overflow onion payments"); }
1298-
match self.format {
1292+
macro_rules! write_onion_hop_data {
1293+
($self: expr, $w: expr) => {
1294+
match $self.format {
12991295
OnionHopDataFormat::Legacy { short_channel_id } => {
1300-
0u8.write(w)?;
1301-
short_channel_id.write(w)?;
1302-
self.amt_to_forward.write(w)?;
1303-
self.outgoing_cltv_value.write(w)?;
1304-
w.write_all(&[0;12])?;
1296+
0u8.write($w)?;
1297+
short_channel_id.write($w)?;
1298+
$self.amt_to_forward.write($w)?;
1299+
$self.outgoing_cltv_value.write($w)?;
1300+
$w.write_all(&[0;12])?;
13051301
},
13061302
OnionHopDataFormat::NonFinalNode { short_channel_id } => {
1307-
encode_varint_length_prefixed_tlv!(w, {
1308-
(2, HighZeroBytesDroppedVarInt(self.amt_to_forward), required),
1309-
(4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value), required),
1303+
encode_varint_length_prefixed_tlv!($w, {
1304+
(2, HighZeroBytesDroppedVarInt($self.amt_to_forward), required),
1305+
(4, HighZeroBytesDroppedVarInt($self.outgoing_cltv_value), required),
13101306
(6, short_channel_id, required)
13111307
});
13121308
},
13131309
OnionHopDataFormat::FinalNode { ref payment_data, ref keysend_preimage } => {
1314-
if let Some(final_data) = payment_data {
1315-
if final_data.total_msat > MAX_VALUE_MSAT { panic!("We should never be sending infinite/overflow onion payments"); }
1316-
}
1317-
encode_varint_length_prefixed_tlv!(w, {
1318-
(2, HighZeroBytesDroppedVarInt(self.amt_to_forward), required),
1319-
(4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value), required),
1310+
encode_varint_length_prefixed_tlv!($w, {
1311+
(2, HighZeroBytesDroppedVarInt($self.amt_to_forward), required),
1312+
(4, HighZeroBytesDroppedVarInt($self.outgoing_cltv_value), required),
13201313
(8, payment_data, option),
13211314
(5482373484, keysend_preimage, option)
13221315
});
13231316
},
13241317
}
1318+
};
1319+
}
1320+
1321+
impl Writeable for OnionHopData {
1322+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
1323+
// Note that this should never be reachable if Rust-Lightning generated the message, as we
1324+
// check values are sane long before we get here, though its possible in the future
1325+
// user-generated messages may hit this.
1326+
if self.amt_to_forward > MAX_VALUE_MSAT {
1327+
panic!("We should never be sending infinite/overflow onion payments");
1328+
}
1329+
1330+
if let OnionHopDataFormat::FinalNode { payment_data: Some(data), .. } = &self.format {
1331+
if data.total_msat > MAX_VALUE_MSAT {
1332+
panic!("We should never be sending infinite/overflow onion payments");
1333+
}
1334+
}
1335+
write_onion_hop_data!(&self, w);
1336+
Ok(())
1337+
}
1338+
}
1339+
1340+
impl OnionHopData {
1341+
#[cfg(test)]
1342+
pub(crate) fn write_without_checks<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
1343+
write_onion_hop_data!(&self, w);
13251344
Ok(())
13261345
}
13271346
}

0 commit comments

Comments
 (0)