Skip to content

Commit 0f79b90

Browse files
Receive payment onions as new InboundPayload instead of OnionHopData
To support route blinding, we want to split OnionHopData into two separate structs, one for inbound onions and one for outbound onions. This is because blinded payloads change the fields present in the onion hop data struct based on whether we're sending vs receiving (outbound onions include encrypted blobs, inbound onions can decrypt those blobs and contain the decrypted fields themselves). In upcoming commits, we'll add variants for blinded payloads to the new InboundPayload enum.
1 parent 21890a3 commit 0f79b90

File tree

4 files changed

+102
-88
lines changed

4 files changed

+102
-88
lines changed

fuzz/src/msg_targets/msg_onion_hop_data.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,19 @@
1010
// This file is auto-generated by gen_target.sh based on msg_target_template.txt
1111
// To modify it, modify msg_target_template.txt and run gen_target.sh instead.
1212

13-
use crate::msg_targets::utils::VecWriter;
1413
use crate::utils::test_logger;
1514

1615
#[inline]
1716
pub fn msg_onion_hop_data_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
18-
test_msg_simple!(lightning::ln::msgs::OnionHopData, data);
17+
use lightning::util::ser::Readable;
18+
let mut r = ::std::io::Cursor::new(data);
19+
let _ = <lightning::ln::msgs::InboundPayload as Readable>::read(&mut r);
1920
}
2021

2122
#[no_mangle]
2223
pub extern "C" fn msg_onion_hop_data_run(data: *const u8, datalen: usize) {
24+
use lightning::util::ser::Readable;
2325
let data = unsafe { std::slice::from_raw_parts(data, datalen) };
24-
test_msg_simple!(lightning::ln::msgs::OnionHopData, data);
26+
let mut r = ::std::io::Cursor::new(data);
27+
let _ = <lightning::ln::msgs::InboundPayload as Readable>::read(&mut r);
2528
}

lightning/src/ln/channelmanager.rs

+41-46
Original file line numberDiff line numberDiff line change
@@ -2617,7 +2617,7 @@ where
26172617
}
26182618

26192619
fn construct_fwd_pending_htlc_info(
2620-
&self, msg: &msgs::UpdateAddHTLC, hop_data: msgs::OnionHopData, hop_hmac: [u8; 32],
2620+
&self, msg: &msgs::UpdateAddHTLC, hop_data: msgs::InboundPayload, hop_hmac: [u8; 32],
26212621
new_packet_bytes: [u8; onion_utils::ONION_DATA_LEN], shared_secret: [u8; 32],
26222622
next_packet_pubkey_opt: Option<Result<PublicKey, secp256k1::Error>>
26232623
) -> Result<PendingHTLCInfo, InboundOnionErr> {
@@ -2626,42 +2626,44 @@ where
26262626
version: 0,
26272627
public_key: next_packet_pubkey_opt.unwrap_or(Err(secp256k1::Error::InvalidPublicKey)),
26282628
hop_data: new_packet_bytes,
2629-
hmac: hop_hmac.clone(),
2629+
hmac: hop_hmac,
26302630
};
26312631

2632-
let short_channel_id = match hop_data.format {
2633-
msgs::OnionHopDataFormat::NonFinalNode { short_channel_id } => short_channel_id,
2634-
msgs::OnionHopDataFormat::FinalNode { .. } => {
2632+
let (short_channel_id, amt_to_forward, outgoing_cltv_value) = match hop_data {
2633+
msgs::InboundPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } =>
2634+
(short_channel_id, amt_to_forward, outgoing_cltv_value),
2635+
msgs::InboundPayload::Receive { .. } =>
26352636
return Err(InboundOnionErr {
26362637
msg: "Final Node OnionHopData provided for us as an intermediary node",
26372638
err_code: 0x4000 | 22,
26382639
err_data: Vec::new(),
2639-
})
2640-
},
2640+
}),
26412641
};
26422642

26432643
Ok(PendingHTLCInfo {
26442644
routing: PendingHTLCRouting::Forward {
26452645
onion_packet: outgoing_packet,
26462646
short_channel_id,
26472647
},
2648-
payment_hash: msg.payment_hash.clone(),
2648+
payment_hash: msg.payment_hash,
26492649
incoming_shared_secret: shared_secret,
26502650
incoming_amt_msat: Some(msg.amount_msat),
2651-
outgoing_amt_msat: hop_data.amt_to_forward,
2652-
outgoing_cltv_value: hop_data.outgoing_cltv_value,
2651+
outgoing_amt_msat: amt_to_forward,
2652+
outgoing_cltv_value,
26532653
skimmed_fee_msat: None,
26542654
})
26552655
}
26562656

26572657
fn construct_recv_pending_htlc_info(
2658-
&self, hop_data: msgs::OnionHopData, shared_secret: [u8; 32], payment_hash: PaymentHash,
2658+
&self, hop_data: msgs::InboundPayload, shared_secret: [u8; 32], payment_hash: PaymentHash,
26592659
amt_msat: u64, cltv_expiry: u32, phantom_shared_secret: Option<[u8; 32]>, allow_underpay: bool,
26602660
counterparty_skimmed_fee_msat: Option<u64>,
26612661
) -> Result<PendingHTLCInfo, InboundOnionErr> {
2662-
let (payment_data, keysend_preimage, payment_metadata) = match hop_data.format {
2663-
msgs::OnionHopDataFormat::FinalNode { payment_data, keysend_preimage, payment_metadata } =>
2664-
(payment_data, keysend_preimage, payment_metadata),
2662+
let (payment_data, keysend_preimage, onion_amt_msat, outgoing_cltv_value, payment_metadata) = match hop_data {
2663+
msgs::InboundPayload::Receive {
2664+
payment_data, keysend_preimage, amt_msat, outgoing_cltv_value, payment_metadata, ..
2665+
} =>
2666+
(payment_data, keysend_preimage, amt_msat, outgoing_cltv_value, payment_metadata),
26652667
_ =>
26662668
return Err(InboundOnionErr {
26672669
err_code: 0x4000|22,
@@ -2670,7 +2672,7 @@ where
26702672
}),
26712673
};
26722674
// final_incorrect_cltv_expiry
2673-
if hop_data.outgoing_cltv_value > cltv_expiry {
2675+
if outgoing_cltv_value > cltv_expiry {
26742676
return Err(InboundOnionErr {
26752677
msg: "Upstream node set CLTV to less than the CLTV set by the sender",
26762678
err_code: 18,
@@ -2685,7 +2687,7 @@ where
26852687
// payment logic has enough time to fail the HTLC backward before our onchain logic triggers a
26862688
// channel closure (see HTLC_FAIL_BACK_BUFFER rationale).
26872689
let current_height: u32 = self.best_block.read().unwrap().height();
2688-
if (hop_data.outgoing_cltv_value as u64) <= current_height as u64 + HTLC_FAIL_BACK_BUFFER as u64 + 1 {
2690+
if (outgoing_cltv_value as u64) <= current_height as u64 + HTLC_FAIL_BACK_BUFFER as u64 + 1 {
26892691
let mut err_data = Vec::with_capacity(12);
26902692
err_data.extend_from_slice(&amt_msat.to_be_bytes());
26912693
err_data.extend_from_slice(&current_height.to_be_bytes());
@@ -2694,8 +2696,8 @@ where
26942696
msg: "The final CLTV expiry is too soon to handle",
26952697
});
26962698
}
2697-
if (!allow_underpay && hop_data.amt_to_forward > amt_msat) ||
2698-
(allow_underpay && hop_data.amt_to_forward >
2699+
if (!allow_underpay && onion_amt_msat > amt_msat) ||
2700+
(allow_underpay && onion_amt_msat >
26992701
amt_msat.saturating_add(counterparty_skimmed_fee_msat.unwrap_or(0)))
27002702
{
27012703
return Err(InboundOnionErr {
@@ -2731,13 +2733,13 @@ where
27312733
payment_data,
27322734
payment_preimage,
27332735
payment_metadata,
2734-
incoming_cltv_expiry: hop_data.outgoing_cltv_value,
2736+
incoming_cltv_expiry: outgoing_cltv_value,
27352737
}
27362738
} else if let Some(data) = payment_data {
27372739
routing = PendingHTLCRouting::Receive {
27382740
payment_data: data,
27392741
payment_metadata,
2740-
incoming_cltv_expiry: hop_data.outgoing_cltv_value,
2742+
incoming_cltv_expiry: outgoing_cltv_value,
27412743
phantom_shared_secret,
27422744
}
27432745
} else {
@@ -2752,8 +2754,8 @@ where
27522754
payment_hash,
27532755
incoming_shared_secret: shared_secret,
27542756
incoming_amt_msat: Some(amt_msat),
2755-
outgoing_amt_msat: hop_data.amt_to_forward,
2756-
outgoing_cltv_value: hop_data.outgoing_cltv_value,
2757+
outgoing_amt_msat: onion_amt_msat,
2758+
outgoing_cltv_value,
27572759
skimmed_fee_msat: counterparty_skimmed_fee_msat,
27582760
})
27592761
}
@@ -2817,9 +2819,8 @@ where
28172819
};
28182820
let (outgoing_scid, outgoing_amt_msat, outgoing_cltv_value, next_packet_pk_opt) = match next_hop {
28192821
onion_utils::Hop::Forward {
2820-
next_hop_data: msgs::OnionHopData {
2821-
format: msgs::OnionHopDataFormat::NonFinalNode { short_channel_id }, amt_to_forward,
2822-
outgoing_cltv_value,
2822+
next_hop_data: msgs::InboundPayload::Forward {
2823+
short_channel_id, amt_to_forward, outgoing_cltv_value
28232824
}, ..
28242825
} => {
28252826
let next_pk = onion_utils::next_hop_packet_pubkey(&self.secp_ctx,
@@ -2829,9 +2830,7 @@ where
28292830
// We'll do receive checks in [`Self::construct_pending_htlc_info`] so we have access to the
28302831
// inbound channel's state.
28312832
onion_utils::Hop::Receive { .. } => return Ok((next_hop, shared_secret, None)),
2832-
onion_utils::Hop::Forward {
2833-
next_hop_data: msgs::OnionHopData { format: msgs::OnionHopDataFormat::FinalNode { .. }, .. }, ..
2834-
} => {
2833+
onion_utils::Hop::Forward { next_hop_data: msgs::InboundPayload::Receive { .. }, .. } => {
28352834
return_err!("Final Node OnionHopData provided for us as an intermediary node", 0x4000 | 22, &[0; 0]);
28362835
}
28372836
};
@@ -10021,16 +10020,14 @@ mod tests {
1002110020
let node = create_network(1, &node_cfg, &node_chanmgr);
1002210021
let sender_intended_amt_msat = 100;
1002310022
let extra_fee_msat = 10;
10024-
let hop_data = msgs::OnionHopData {
10025-
amt_to_forward: 100,
10023+
let hop_data = msgs::InboundPayload::Receive {
10024+
amt_msat: 100,
1002610025
outgoing_cltv_value: 42,
10027-
format: msgs::OnionHopDataFormat::FinalNode {
10028-
keysend_preimage: None,
10029-
payment_metadata: None,
10030-
payment_data: Some(msgs::FinalOnionHopData {
10031-
payment_secret: PaymentSecret([0; 32]), total_msat: sender_intended_amt_msat,
10032-
}),
10033-
}
10026+
payment_metadata: None,
10027+
keysend_preimage: None,
10028+
payment_data: Some(msgs::FinalOnionHopData {
10029+
payment_secret: PaymentSecret([0; 32]), total_msat: sender_intended_amt_msat,
10030+
}),
1003410031
};
1003510032
// Check that if the amount we received + the penultimate hop extra fee is less than the sender
1003610033
// intended amount, we fail the payment.
@@ -10042,16 +10039,14 @@ mod tests {
1004210039
} else { panic!(); }
1004310040

1004410041
// If amt_received + extra_fee is equal to the sender intended amount, we're fine.
10045-
let hop_data = msgs::OnionHopData { // This is the same hop_data as above, OnionHopData doesn't implement Clone
10046-
amt_to_forward: 100,
10042+
let hop_data = msgs::InboundPayload::Receive { // This is the same payload as above, InboundPayload doesn't implement Clone
10043+
amt_msat: 100,
1004710044
outgoing_cltv_value: 42,
10048-
format: msgs::OnionHopDataFormat::FinalNode {
10049-
keysend_preimage: None,
10050-
payment_metadata: None,
10051-
payment_data: Some(msgs::FinalOnionHopData {
10052-
payment_secret: PaymentSecret([0; 32]), total_msat: sender_intended_amt_msat,
10053-
}),
10054-
}
10045+
payment_metadata: None,
10046+
keysend_preimage: None,
10047+
payment_data: Some(msgs::FinalOnionHopData {
10048+
payment_secret: PaymentSecret([0; 32]), total_msat: sender_intended_amt_msat,
10049+
}),
1005510050
};
1005610051
assert!(node[0].node.construct_recv_pending_htlc_info(hop_data, [0; 32], PaymentHash([0; 32]),
1005710052
sender_intended_amt_msat - extra_fee_msat, 42, None, true, Some(extra_fee_msat)).is_ok());

0 commit comments

Comments
 (0)