1use bitcoin::hashes::sha256::Hash as Sha256;
7use bitcoin::hashes::Hash;
8use bitcoin::secp256k1::ecdh::SharedSecret;
9use bitcoin::secp256k1::{self, PublicKey, Secp256k1};
10
11use crate::blinded_path;
12use crate::blinded_path::payment::{PaymentConstraints, PaymentRelay};
13use crate::chain::channelmonitor::{HTLC_FAIL_BACK_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS};
14use crate::ln::channelmanager::{
15 BlindedFailure, BlindedForward, HTLCFailureMsg, PendingHTLCInfo, PendingHTLCRouting,
16 CLTV_FAR_FAR_AWAY, MIN_CLTV_EXPIRY_DELTA,
17};
18use crate::ln::msgs;
19use crate::ln::onion_utils;
20use crate::ln::onion_utils::{HTLCFailReason, LocalHTLCFailureReason, ONION_DATA_LEN};
21use crate::sign::{NodeSigner, Recipient};
22use crate::types::features::BlindedHopFeatures;
23use crate::types::payment::PaymentHash;
24use crate::util::logger::Logger;
25
26#[allow(unused_imports)]
27use crate::prelude::*;
28
29use core::ops::Deref;
30
31#[derive(Clone, Debug, Hash, PartialEq, Eq)]
33pub struct InboundHTLCErr {
34 pub reason: LocalHTLCFailureReason,
36 pub err_data: Vec<u8>,
38 pub msg: &'static str,
40}
41
42pub(super) fn invalid_payment_err_data(amt_msat: u64, current_height: u32) -> Vec<u8> {
44 let mut err_data = Vec::with_capacity(12);
45 err_data.extend_from_slice(&amt_msat.to_be_bytes());
46 err_data.extend_from_slice(¤t_height.to_be_bytes());
47 err_data
48}
49
50#[rustfmt::skip]
51fn check_blinded_payment_constraints(
52 amt_msat: u64, cltv_expiry: u32, constraints: &PaymentConstraints
53) -> Result<(), ()> {
54 if amt_msat < constraints.htlc_minimum_msat ||
55 cltv_expiry > constraints.max_cltv_expiry
56 { return Err(()) }
57 Ok(())
58}
59
60#[rustfmt::skip]
61fn check_blinded_forward(
62 inbound_amt_msat: u64, inbound_cltv_expiry: u32, payment_relay: &PaymentRelay,
63 payment_constraints: &PaymentConstraints, features: &BlindedHopFeatures
64) -> Result<(u64, u32), ()> {
65 let amt_to_forward = blinded_path::payment::amt_to_forward_msat(
66 inbound_amt_msat, payment_relay
67 ).ok_or(())?;
68 let outgoing_cltv_value = inbound_cltv_expiry.checked_sub(
69 payment_relay.cltv_expiry_delta as u32
70 ).ok_or(())?;
71 check_blinded_payment_constraints(inbound_amt_msat, outgoing_cltv_value, payment_constraints)?;
72
73 if features.requires_unknown_bits_from(&BlindedHopFeatures::empty()) { return Err(()) }
74 Ok((amt_to_forward, outgoing_cltv_value))
75}
76
77enum RoutingInfo {
78 Direct {
79 short_channel_id: u64,
80 new_packet_bytes: [u8; ONION_DATA_LEN],
81 next_hop_hmac: [u8; 32],
82 },
83 Trampoline {
84 next_trampoline: PublicKey,
85 new_packet_bytes: Vec<u8>,
87 next_hop_hmac: [u8; 32],
88 shared_secret: SharedSecret,
89 current_path_key: Option<PublicKey>,
90 },
91}
92
93#[rustfmt::skip]
94pub(super) fn create_fwd_pending_htlc_info(
95 msg: &msgs::UpdateAddHTLC, hop_data: onion_utils::Hop, shared_secret: [u8; 32],
96 next_packet_pubkey_opt: Option<Result<PublicKey, secp256k1::Error>>
97) -> Result<PendingHTLCInfo, InboundHTLCErr> {
98 debug_assert!(next_packet_pubkey_opt.is_some());
99
100 let (
101 routing_info, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point,
102 next_blinding_override
103 ) = match hop_data {
104 onion_utils::Hop::Forward { next_hop_data: msgs::InboundOnionForwardPayload {
105 short_channel_id, amt_to_forward, outgoing_cltv_value
106 }, new_packet_bytes, next_hop_hmac, .. } =>
107 (RoutingInfo::Direct { short_channel_id, new_packet_bytes, next_hop_hmac }, amt_to_forward, outgoing_cltv_value, None, None),
108 onion_utils::Hop::BlindedForward { next_hop_data: msgs::InboundOnionBlindedForwardPayload {
109 short_channel_id, payment_relay, payment_constraints, intro_node_blinding_point, features,
110 next_blinding_override,
111 }, new_packet_bytes, next_hop_hmac, .. } => {
112 let (amt_to_forward, outgoing_cltv_value) = check_blinded_forward(
113 msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features
114 ).map_err(|()| {
115 InboundHTLCErr {
118 msg: "Underflow calculating outbound amount or cltv value for blinded forward",
119 reason: LocalHTLCFailureReason::InvalidOnionBlinding,
120 err_data: vec![0; 32],
121 }
122 })?;
123 (RoutingInfo::Direct { short_channel_id, new_packet_bytes, next_hop_hmac }, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point,
124 next_blinding_override)
125 },
126 onion_utils::Hop::Receive { .. } | onion_utils::Hop::BlindedReceive { .. } =>
127 return Err(InboundHTLCErr {
128 msg: "Final Node OnionHopData provided for us as an intermediary node",
129 reason: LocalHTLCFailureReason::InvalidOnionPayload,
130 err_data: Vec::new(),
131 }),
132 onion_utils::Hop::TrampolineReceive { .. } | onion_utils::Hop::TrampolineBlindedReceive { .. } =>
133 return Err(InboundHTLCErr {
134 msg: "Final Node OnionHopData provided for us as an intermediary node",
135 reason: LocalHTLCFailureReason::InvalidOnionPayload,
136 err_data: Vec::new(),
137 }),
138 onion_utils::Hop::TrampolineForward { next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
139 (
140 RoutingInfo::Trampoline {
141 next_trampoline: next_trampoline_hop_data.next_trampoline,
142 new_packet_bytes: new_trampoline_packet_bytes,
143 next_hop_hmac: next_trampoline_hop_hmac,
144 shared_secret: trampoline_shared_secret,
145 current_path_key: None
146 },
147 next_trampoline_hop_data.amt_to_forward,
148 next_trampoline_hop_data.outgoing_cltv_value,
149 None,
150 None
151 )
152 },
153 onion_utils::Hop::TrampolineBlindedForward { outer_hop_data, next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
154 let (amt_to_forward, outgoing_cltv_value) = check_blinded_forward(
155 msg.amount_msat, msg.cltv_expiry, &next_trampoline_hop_data.payment_relay, &next_trampoline_hop_data.payment_constraints, &next_trampoline_hop_data.features
156 ).map_err(|()| {
157 InboundHTLCErr {
160 msg: "Underflow calculating outbound amount or cltv value for blinded forward",
161 reason: LocalHTLCFailureReason::InvalidOnionBlinding,
162 err_data: vec![0; 32],
163 }
164 })?;
165 (
166 RoutingInfo::Trampoline {
167 next_trampoline: next_trampoline_hop_data.next_trampoline,
168 new_packet_bytes: new_trampoline_packet_bytes,
169 next_hop_hmac: next_trampoline_hop_hmac,
170 shared_secret: trampoline_shared_secret,
171 current_path_key: outer_hop_data.current_path_key
172 },
173 amt_to_forward,
174 outgoing_cltv_value,
175 next_trampoline_hop_data.intro_node_blinding_point,
176 next_trampoline_hop_data.next_blinding_override
177 )
178 },
179 };
180
181 let routing = match routing_info {
182 RoutingInfo::Direct { short_channel_id, new_packet_bytes, next_hop_hmac } => {
183 let outgoing_packet = msgs::OnionPacket {
184 version: 0,
185 public_key: next_packet_pubkey_opt.unwrap_or(Err(secp256k1::Error::InvalidPublicKey)),
186 hop_data: new_packet_bytes,
187 hmac: next_hop_hmac,
188 };
189 PendingHTLCRouting::Forward {
190 onion_packet: outgoing_packet,
191 short_channel_id,
192 incoming_cltv_expiry: Some(msg.cltv_expiry),
193 hold_htlc: msg.hold_htlc,
194 blinded: intro_node_blinding_point.or(msg.blinding_point)
195 .map(|bp| BlindedForward {
196 inbound_blinding_point: bp,
197 next_blinding_override,
198 failure: intro_node_blinding_point
199 .map(|_| BlindedFailure::FromIntroductionNode)
200 .unwrap_or(BlindedFailure::FromBlindedNode),
201 }),
202 }
203 }
204 RoutingInfo::Trampoline { next_trampoline, new_packet_bytes, next_hop_hmac, shared_secret, current_path_key } => {
205 let next_trampoline_packet_pubkey = match next_packet_pubkey_opt {
206 Some(Ok(pubkey)) => pubkey,
207 _ => return Err(InboundHTLCErr {
208 msg: "Missing next Trampoline hop pubkey from intermediate Trampoline forwarding data",
209 reason: LocalHTLCFailureReason::InvalidTrampolinePayload,
210 err_data: Vec::new(),
211 }),
212 };
213 let outgoing_packet = msgs::TrampolineOnionPacket {
214 version: 0,
215 public_key: next_trampoline_packet_pubkey,
216 hop_data: new_packet_bytes,
217 hmac: next_hop_hmac,
218 };
219 PendingHTLCRouting::TrampolineForward {
220 incoming_shared_secret: shared_secret.secret_bytes(),
221 onion_packet: outgoing_packet,
222 node_id: next_trampoline,
223 incoming_cltv_expiry: msg.cltv_expiry,
224 blinded: intro_node_blinding_point.or(current_path_key)
225 .map(|bp| BlindedForward {
226 inbound_blinding_point: bp,
227 next_blinding_override,
228 failure: intro_node_blinding_point
229 .map(|_| BlindedFailure::FromIntroductionNode)
230 .unwrap_or(BlindedFailure::FromBlindedNode),
231 })
232 }
233 }
234 };
235
236 Ok(PendingHTLCInfo {
237 routing,
238 payment_hash: msg.payment_hash,
239 incoming_shared_secret: shared_secret,
240 incoming_amt_msat: Some(msg.amount_msat),
241 outgoing_amt_msat: amt_to_forward,
242 outgoing_cltv_value,
243 skimmed_fee_msat: None,
244 })
245}
246
247#[rustfmt::skip]
248pub(super) fn create_recv_pending_htlc_info(
249 hop_data: onion_utils::Hop, shared_secret: [u8; 32], payment_hash: PaymentHash,
250 amt_msat: u64, cltv_expiry: u32, phantom_shared_secret: Option<[u8; 32]>, allow_underpay: bool,
251 counterparty_skimmed_fee_msat: Option<u64>, current_height: u32
252) -> Result<PendingHTLCInfo, InboundHTLCErr> {
253 let (
254 payment_data, keysend_preimage, custom_tlvs, onion_amt_msat, onion_cltv_expiry,
255 payment_metadata, payment_context, requires_blinded_error, has_recipient_created_payment_secret,
256 invoice_request
257 ) = match hop_data {
258 onion_utils::Hop::Receive { hop_data: msgs::InboundOnionReceivePayload {
259 payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
260 cltv_expiry_height, payment_metadata, ..
261 }, .. } =>
262 (payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
263 cltv_expiry_height, payment_metadata, None, false, keysend_preimage.is_none(), None),
264 onion_utils::Hop::BlindedReceive { hop_data: msgs::InboundOnionBlindedReceivePayload {
265 sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, payment_secret,
266 intro_node_blinding_point, payment_constraints, payment_context, keysend_preimage,
267 custom_tlvs, invoice_request
268 }, .. } => {
269 check_blinded_payment_constraints(
270 sender_intended_htlc_amt_msat, cltv_expiry, &payment_constraints
271 )
272 .map_err(|()| {
273 InboundHTLCErr {
274 reason: LocalHTLCFailureReason::InvalidOnionBlinding,
275 err_data: vec![0; 32],
276 msg: "Amount or cltv_expiry violated blinded payment constraints",
277 }
278 })?;
279 let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat };
280 (Some(payment_data), keysend_preimage, custom_tlvs,
281 sender_intended_htlc_amt_msat, cltv_expiry_height, None, Some(payment_context),
282 intro_node_blinding_point.is_none(), true, invoice_request)
283 }
284 onion_utils::Hop::TrampolineReceive {
285 trampoline_hop_data: msgs::InboundOnionReceivePayload {
286 payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
287 cltv_expiry_height, payment_metadata, ..
288 }, ..
289 } =>
290 (payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
291 cltv_expiry_height, payment_metadata, None, false, keysend_preimage.is_none(), None),
292 onion_utils::Hop::TrampolineBlindedReceive {
293 trampoline_hop_data: msgs::InboundOnionBlindedReceivePayload {
294 sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, payment_secret,
295 intro_node_blinding_point, payment_constraints, payment_context, keysend_preimage,
296 custom_tlvs, invoice_request
297 }, ..
298 } => {
299 check_blinded_payment_constraints(
300 sender_intended_htlc_amt_msat, cltv_expiry, &payment_constraints,
301 )
302 .map_err(|()| {
303 InboundHTLCErr {
304 reason: LocalHTLCFailureReason::InvalidOnionBlinding,
305 err_data: vec![0; 32],
306 msg: "Amount or cltv_expiry violated blinded payment constraints within Trampoline onion",
307 }
308 })?;
309 let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat };
310 (Some(payment_data), keysend_preimage, custom_tlvs,
311 sender_intended_htlc_amt_msat, cltv_expiry_height, None, Some(payment_context),
312 intro_node_blinding_point.is_none(), true, invoice_request)
313 },
314 onion_utils::Hop::Forward { .. } => {
315 return Err(InboundHTLCErr {
316 reason: LocalHTLCFailureReason::InvalidOnionPayload,
317 err_data: Vec::new(),
318 msg: "Got non final data with an HMAC of 0",
319 })
320 },
321 onion_utils::Hop::BlindedForward { .. } => {
322 return Err(InboundHTLCErr {
323 reason: LocalHTLCFailureReason::InvalidOnionBlinding,
324 err_data: vec![0; 32],
325 msg: "Got blinded non final data with an HMAC of 0",
326 })
327 },
328 onion_utils::Hop::TrampolineForward { .. } | onion_utils::Hop::TrampolineBlindedForward { .. } => {
329 return Err(InboundHTLCErr {
330 reason: LocalHTLCFailureReason::InvalidOnionPayload,
331 err_data: Vec::new(),
332 msg: "Got Trampoline non final data with an HMAC of 0",
333 })
334 },
335 };
336 if onion_cltv_expiry > cltv_expiry {
338 return Err(InboundHTLCErr {
339 msg: "Upstream node set CLTV to less than the CLTV set by the sender",
340 reason: LocalHTLCFailureReason::FinalIncorrectCLTVExpiry,
341 err_data: cltv_expiry.to_be_bytes().to_vec()
342 })
343 }
344 if cltv_expiry <= current_height + HTLC_FAIL_BACK_BUFFER + 1 {
352 return Err(InboundHTLCErr {
353 reason: LocalHTLCFailureReason::PaymentClaimBuffer,
354 err_data: invalid_payment_err_data(amt_msat, current_height),
355 msg: "The final CLTV expiry is too soon to handle",
356 });
357 }
358 if (!allow_underpay && onion_amt_msat > amt_msat) ||
359 (allow_underpay && onion_amt_msat >
360 amt_msat.saturating_add(counterparty_skimmed_fee_msat.unwrap_or(0)))
361 {
362 return Err(InboundHTLCErr {
363 reason: LocalHTLCFailureReason::FinalIncorrectHTLCAmount,
364 err_data: amt_msat.to_be_bytes().to_vec(),
365 msg: "Upstream node sent less than we were supposed to receive in payment",
366 });
367 }
368
369 let routing = if let Some(payment_preimage) = keysend_preimage {
370 let hashed_preimage = PaymentHash(Sha256::hash(&payment_preimage.0).to_byte_array());
376 if hashed_preimage != payment_hash {
377 return Err(InboundHTLCErr {
378 reason: LocalHTLCFailureReason::InvalidKeysendPreimage,
379 err_data: invalid_payment_err_data(amt_msat, current_height),
380 msg: "Payment preimage didn't match payment hash",
381 });
382 }
383 PendingHTLCRouting::ReceiveKeysend {
384 payment_data,
385 payment_preimage,
386 payment_metadata,
387 incoming_cltv_expiry: onion_cltv_expiry,
388 custom_tlvs,
389 requires_blinded_error,
390 has_recipient_created_payment_secret,
391 payment_context,
392 invoice_request,
393 }
394 } else if let Some(data) = payment_data {
395 PendingHTLCRouting::Receive {
396 payment_data: data,
397 payment_metadata,
398 payment_context,
399 incoming_cltv_expiry: onion_cltv_expiry,
400 phantom_shared_secret,
401 custom_tlvs,
402 requires_blinded_error,
403 }
404 } else {
405 return Err(InboundHTLCErr {
406 reason: LocalHTLCFailureReason::PaymentSecretRequired,
407 err_data: Vec::new(),
408 msg: "We require payment_secrets",
409 });
410 };
411 Ok(PendingHTLCInfo {
412 routing,
413 payment_hash,
414 incoming_shared_secret: shared_secret,
415 incoming_amt_msat: Some(amt_msat),
416 outgoing_amt_msat: onion_amt_msat,
417 outgoing_cltv_value: onion_cltv_expiry,
418 skimmed_fee_msat: counterparty_skimmed_fee_msat,
419 })
420}
421
422#[rustfmt::skip]
432pub fn peel_payment_onion<NS: Deref, L: Deref, T: secp256k1::Verification>(
433 msg: &msgs::UpdateAddHTLC, node_signer: NS, logger: L, secp_ctx: &Secp256k1<T>,
434 cur_height: u32, allow_skimmed_fees: bool,
435) -> Result<PendingHTLCInfo, InboundHTLCErr>
436where
437 NS::Target: NodeSigner,
438 L::Target: Logger,
439{
440 let (hop, next_packet_details_opt) =
441 decode_incoming_update_add_htlc_onion(msg, node_signer, logger, secp_ctx
442 ).map_err(|(msg, failure_reason)| {
443 let (reason, err_data) = match msg {
444 HTLCFailureMsg::Malformed(_) => (failure_reason, Vec::new()),
445 HTLCFailureMsg::Relay(r) => (LocalHTLCFailureReason::InvalidOnionPayload, r.reason),
446 };
447 let msg = "Failed to decode update add htlc onion";
448 InboundHTLCErr { msg, reason, err_data }
449 })?;
450 Ok(match hop {
451 onion_utils::Hop::Forward { shared_secret, .. } |
452 onion_utils::Hop::BlindedForward { shared_secret, .. } => {
453 let NextPacketDetails {
454 next_packet_pubkey, outgoing_amt_msat: _, outgoing_connector: _, outgoing_cltv_value
455 } = match next_packet_details_opt {
456 Some(next_packet_details) => next_packet_details,
457 None => return Err(InboundHTLCErr {
459 msg: "Failed to decode update add htlc onion",
460 reason: LocalHTLCFailureReason::InvalidOnionPayload,
461 err_data: Vec::new(),
462 }),
463 };
464
465 if let Err(reason) = check_incoming_htlc_cltv(
466 cur_height, outgoing_cltv_value, msg.cltv_expiry,
467 ) {
468 return Err(InboundHTLCErr {
469 msg: "incoming cltv check failed",
470 reason,
471 err_data: Vec::new(),
472 });
473 }
474
475 create_fwd_pending_htlc_info(msg, hop, shared_secret.secret_bytes(), Some(next_packet_pubkey))?
478 },
479 _ => {
480 let shared_secret = hop.shared_secret().secret_bytes();
481 create_recv_pending_htlc_info(
482 hop, shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry,
483 None, allow_skimmed_fees, msg.skimmed_fee_msat, cur_height,
484 )?
485 }
486 })
487}
488
489pub(super) enum HopConnector {
490 ShortChannelId(u64),
492 #[allow(unused)]
494 Trampoline(PublicKey),
495}
496
497pub(super) struct NextPacketDetails {
498 pub(super) next_packet_pubkey: Result<PublicKey, secp256k1::Error>,
499 pub(super) outgoing_connector: HopConnector,
500 pub(super) outgoing_amt_msat: u64,
501 pub(super) outgoing_cltv_value: u32,
502}
503
504#[rustfmt::skip]
505pub(super) fn decode_incoming_update_add_htlc_onion<NS: Deref, L: Deref, T: secp256k1::Verification>(
506 msg: &msgs::UpdateAddHTLC, node_signer: NS, logger: L, secp_ctx: &Secp256k1<T>,
507) -> Result<(onion_utils::Hop, Option<NextPacketDetails>), (HTLCFailureMsg, LocalHTLCFailureReason)>
508where
509 NS::Target: NodeSigner,
510 L::Target: Logger,
511{
512 let encode_malformed_error = |message: &str, failure_reason: LocalHTLCFailureReason| {
513 log_info!(logger, "Failed to accept/forward incoming HTLC: {}", message);
514 let (sha256_of_onion, failure_reason) = if msg.blinding_point.is_some() || failure_reason == LocalHTLCFailureReason::InvalidOnionBlinding {
515 ([0; 32], LocalHTLCFailureReason::InvalidOnionBlinding)
516 } else {
517 (Sha256::hash(&msg.onion_routing_packet.hop_data).to_byte_array(), failure_reason)
518 };
519 return Err((HTLCFailureMsg::Malformed(msgs::UpdateFailMalformedHTLC {
520 channel_id: msg.channel_id,
521 htlc_id: msg.htlc_id,
522 sha256_of_onion,
523 failure_code: failure_reason.failure_code(),
524 }), failure_reason));
525 };
526
527 if let Err(_) = msg.onion_routing_packet.public_key {
528 return encode_malformed_error("invalid ephemeral pubkey", LocalHTLCFailureReason::InvalidOnionKey);
529 }
530
531 if msg.onion_routing_packet.version != 0 {
532 return encode_malformed_error("Unknown onion packet version", LocalHTLCFailureReason::InvalidOnionVersion)
539 }
540
541 let encode_relay_error = |message: &str, reason: LocalHTLCFailureReason, shared_secret: [u8; 32], trampoline_shared_secret: Option<[u8; 32]>, data: &[u8]| {
542 if msg.blinding_point.is_some() {
543 return encode_malformed_error(message, LocalHTLCFailureReason::InvalidOnionBlinding)
544 }
545
546 log_info!(logger, "Failed to accept/forward incoming HTLC: {}", message);
547 let failure = HTLCFailReason::reason(reason, data.to_vec())
548 .get_encrypted_failure_packet(&shared_secret, &trampoline_shared_secret);
549 return Err((HTLCFailureMsg::Relay(msgs::UpdateFailHTLC {
550 channel_id: msg.channel_id,
551 htlc_id: msg.htlc_id,
552 reason: failure.data,
553 attribution_data: failure.attribution_data,
554 }), reason));
555 };
556
557 let next_hop = match onion_utils::decode_next_payment_hop(
558 Recipient::Node, &msg.onion_routing_packet.public_key.unwrap(), &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac,
559 msg.payment_hash, msg.blinding_point, node_signer
560 ) {
561 Ok(res) => res,
562 Err(onion_utils::OnionDecodeErr::Malformed { err_msg, reason }) => {
563 return encode_malformed_error(err_msg, reason);
564 },
565 Err(onion_utils::OnionDecodeErr::Relay { err_msg, reason, shared_secret, trampoline_shared_secret }) => {
566 return encode_relay_error(err_msg, reason, shared_secret.secret_bytes(), trampoline_shared_secret.map(|tss| tss.secret_bytes()), &[0; 0]);
567 },
568 };
569
570 let next_packet_details = match next_hop {
571 onion_utils::Hop::Forward { next_hop_data: msgs::InboundOnionForwardPayload { short_channel_id, amt_to_forward, outgoing_cltv_value }, shared_secret, .. } => {
572 let next_packet_pubkey = onion_utils::next_hop_pubkey(secp_ctx,
573 msg.onion_routing_packet.public_key.unwrap(), &shared_secret.secret_bytes());
574 Some(NextPacketDetails {
575 next_packet_pubkey, outgoing_connector: HopConnector::ShortChannelId(short_channel_id),
576 outgoing_amt_msat: amt_to_forward, outgoing_cltv_value
577 })
578 }
579 onion_utils::Hop::BlindedForward { next_hop_data: msgs::InboundOnionBlindedForwardPayload { short_channel_id, ref payment_relay, ref payment_constraints, ref features, .. }, shared_secret, .. } => {
580 let (amt_to_forward, outgoing_cltv_value) = match check_blinded_forward(
581 msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features
582 ) {
583 Ok((amt, cltv)) => (amt, cltv),
584 Err(()) => {
585 return encode_relay_error("Underflow calculating outbound amount or cltv value for blinded forward",
586 LocalHTLCFailureReason::InvalidOnionBlinding, shared_secret.secret_bytes(), None, &[0; 32]);
587 }
588 };
589 let next_packet_pubkey = onion_utils::next_hop_pubkey(&secp_ctx,
590 msg.onion_routing_packet.public_key.unwrap(), &shared_secret.secret_bytes());
591 Some(NextPacketDetails {
592 next_packet_pubkey, outgoing_connector: HopConnector::ShortChannelId(short_channel_id), outgoing_amt_msat: amt_to_forward,
593 outgoing_cltv_value
594 })
595 }
596 onion_utils::Hop::TrampolineForward { next_trampoline_hop_data: msgs::InboundTrampolineForwardPayload { amt_to_forward, outgoing_cltv_value, next_trampoline }, trampoline_shared_secret, incoming_trampoline_public_key, .. } => {
597 let next_trampoline_packet_pubkey = onion_utils::next_hop_pubkey(secp_ctx,
598 incoming_trampoline_public_key, &trampoline_shared_secret.secret_bytes());
599 Some(NextPacketDetails {
600 next_packet_pubkey: next_trampoline_packet_pubkey,
601 outgoing_connector: HopConnector::Trampoline(next_trampoline),
602 outgoing_amt_msat: amt_to_forward,
603 outgoing_cltv_value,
604 })
605 }
606 _ => None
607 };
608
609 Ok((next_hop, next_packet_details))
610}
611
612pub(super) fn check_incoming_htlc_cltv(
613 cur_height: u32, outgoing_cltv_value: u32, cltv_expiry: u32,
614) -> Result<(), LocalHTLCFailureReason> {
615 if (cltv_expiry as u64) < (outgoing_cltv_value) as u64 + MIN_CLTV_EXPIRY_DELTA as u64 {
616 return Err(LocalHTLCFailureReason::IncorrectCLTVExpiry);
617 }
618 if cltv_expiry <= cur_height + HTLC_FAIL_BACK_BUFFER as u32 {
622 return Err(LocalHTLCFailureReason::CLTVExpiryTooSoon);
623 }
624 if cltv_expiry > cur_height + CLTV_FAR_FAR_AWAY as u32 {
625 return Err(LocalHTLCFailureReason::CLTVExpiryTooFar);
626 }
627 if (outgoing_cltv_value) as u64 <= (cur_height + LATENCY_GRACE_PERIOD_BLOCKS) as u64 {
636 return Err(LocalHTLCFailureReason::OutgoingCLTVTooSoon);
637 }
638
639 Ok(())
640}
641
642#[cfg(test)]
643mod tests {
644 use crate::ln::channelmanager::{RecipientOnionFields, MIN_CLTV_EXPIRY_DELTA};
645 use crate::ln::functional_test_utils::TEST_FINAL_CLTV;
646 use crate::ln::msgs;
647 use crate::ln::onion_utils::create_payment_onion;
648 use crate::ln::types::ChannelId;
649 use crate::routing::router::{Path, RouteHop};
650 use crate::types::features::{ChannelFeatures, NodeFeatures};
651 use crate::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
652 use crate::util::test_utils;
653 use bitcoin::hashes::sha256::Hash as Sha256;
654 use bitcoin::hashes::Hash;
655 use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
656
657 #[test]
658 #[rustfmt::skip]
659 fn fail_construct_onion_on_too_big_payloads() {
660 let secp_ctx = Secp256k1::new();
666 let bob = crate::sign::KeysManager::new(&[2; 32], 42, 42, true);
667 let bob_pk = PublicKey::from_secret_key(&secp_ctx, &bob.get_node_secret_key());
668 let charlie = crate::sign::KeysManager::new(&[3; 32], 42, 42, true);
669 let charlie_pk = PublicKey::from_secret_key(&secp_ctx, &charlie.get_node_secret_key());
670
671 let (
672 session_priv, total_amt_msat, cur_height, mut recipient_onion, keysend_preimage, payment_hash,
673 prng_seed, hops, ..
674 ) = payment_onion_args(bob_pk, charlie_pk);
675
676 recipient_onion.custom_tlvs.push((13377331, vec![0; 1156]));
678
679 let path = Path { hops, blinded_tail: None, };
680 let onion_keys = super::onion_utils::construct_onion_keys(&secp_ctx, &path, &session_priv);
681 let (onion_payloads, ..) = super::onion_utils::build_onion_payloads(
682 &path, total_amt_msat, &recipient_onion, cur_height + 1, &Some(keysend_preimage), None, None
683 ).unwrap();
684
685 assert!(super::onion_utils::construct_onion_packet(
686 onion_payloads, onion_keys, prng_seed, &payment_hash
687 ).is_err());
688 }
689
690 #[test]
691 #[rustfmt::skip]
692 fn test_peel_payment_onion() {
693 use super::*;
694 let secp_ctx = Secp256k1::new();
695
696 let bob = crate::sign::KeysManager::new(&[2; 32], 42, 42, true);
697 let bob_pk = PublicKey::from_secret_key(&secp_ctx, &bob.get_node_secret_key());
698 let charlie = crate::sign::KeysManager::new(&[3; 32], 42, 42, true);
699 let charlie_pk = PublicKey::from_secret_key(&secp_ctx, &charlie.get_node_secret_key());
700
701 let (session_priv, total_amt_msat, cur_height, recipient_onion, preimage, payment_hash,
702 prng_seed, hops, recipient_amount, pay_secret) = payment_onion_args(bob_pk, charlie_pk);
703
704 let path = Path {
705 hops: hops,
706 blinded_tail: None,
707 };
708
709 let (onion, amount_msat, cltv_expiry) = create_payment_onion(
710 &secp_ctx, &path, &session_priv, total_amt_msat, &recipient_onion,
711 cur_height, &payment_hash, &Some(preimage), None, prng_seed
712 ).unwrap();
713
714 let msg = make_update_add_msg(amount_msat, cltv_expiry, payment_hash, onion);
715 let logger = test_utils::TestLogger::with_id("bob".to_string());
716
717 let peeled = peel_payment_onion(&msg, &bob, &logger, &secp_ctx, cur_height, false)
718 .map_err(|e| e.msg).unwrap();
719
720 let next_onion = match peeled.routing {
721 PendingHTLCRouting::Forward { onion_packet, .. } => {
722 onion_packet
723 },
724 _ => panic!("expected a forwarded onion"),
725 };
726
727 let msg2 = make_update_add_msg(amount_msat, cltv_expiry, payment_hash, next_onion);
728 let peeled2 = peel_payment_onion(&msg2, &charlie, &logger, &secp_ctx, cur_height, false)
729 .map_err(|e| e.msg).unwrap();
730
731 match peeled2.routing {
732 PendingHTLCRouting::ReceiveKeysend { payment_preimage, payment_data, incoming_cltv_expiry, .. } => {
733 assert_eq!(payment_preimage, preimage);
734 assert_eq!(peeled2.outgoing_amt_msat, recipient_amount);
735 assert_eq!(incoming_cltv_expiry, peeled2.outgoing_cltv_value);
736 let msgs::FinalOnionHopData{total_msat, payment_secret} = payment_data.unwrap();
737 assert_eq!(total_msat, total_amt_msat);
738 assert_eq!(payment_secret, pay_secret);
739 },
740 _ => panic!("expected a received keysend"),
741 };
742 }
743
744 fn make_update_add_msg(
745 amount_msat: u64, cltv_expiry: u32, payment_hash: PaymentHash,
746 onion_routing_packet: msgs::OnionPacket,
747 ) -> msgs::UpdateAddHTLC {
748 msgs::UpdateAddHTLC {
749 channel_id: ChannelId::from_bytes([0; 32]),
750 htlc_id: 0,
751 amount_msat,
752 cltv_expiry,
753 payment_hash,
754 onion_routing_packet,
755 skimmed_fee_msat: None,
756 blinding_point: None,
757 hold_htlc: None,
758 }
759 }
760
761 #[rustfmt::skip]
762 fn payment_onion_args(hop_pk: PublicKey, recipient_pk: PublicKey) -> (
763 SecretKey, u64, u32, RecipientOnionFields, PaymentPreimage, PaymentHash, [u8; 32],
764 Vec<RouteHop>, u64, PaymentSecret,
765 ) {
766 let session_priv_bytes = [42; 32];
767 let session_priv = SecretKey::from_slice(&session_priv_bytes).unwrap();
768 let total_amt_msat = 1000;
769 let cur_height = 1000;
770 let pay_secret = PaymentSecret([99; 32]);
771 let recipient_onion = RecipientOnionFields::secret_only(pay_secret);
772 let preimage_bytes = [43; 32];
773 let preimage = PaymentPreimage(preimage_bytes);
774 let rhash_bytes = Sha256::hash(&preimage_bytes).to_byte_array();
775 let payment_hash = PaymentHash(rhash_bytes);
776 let prng_seed = [44; 32];
777
778 let hop_fee = 1;
780 let recipient_amount = total_amt_msat - hop_fee;
781 let hops = vec![
782 RouteHop {
783 pubkey: hop_pk,
784 fee_msat: hop_fee,
785 cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA as u32,
786 short_channel_id: 1,
787 node_features: NodeFeatures::empty(),
788 channel_features: ChannelFeatures::empty(),
789 maybe_announced_channel: false,
790 },
791 RouteHop {
792 pubkey: recipient_pk,
793 fee_msat: recipient_amount,
794 cltv_expiry_delta: TEST_FINAL_CLTV,
795 short_channel_id: 2,
796 node_features: NodeFeatures::empty(),
797 channel_features: ChannelFeatures::empty(),
798 maybe_announced_channel: false,
799 }
800 ];
801
802 (session_priv, total_amt_msat, cur_height, recipient_onion, preimage, payment_hash,
803 prng_seed, hops, recipient_amount, pay_secret)
804 }
805}