1use bitcoin::hashes::{Hash, HashEngine};
7use bitcoin::hashes::hmac::{Hmac, HmacEngine};
8use bitcoin::hashes::sha256::Hash as Sha256;
9use bitcoin::secp256k1::{self, PublicKey, Scalar, 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::types::payment::PaymentHash;
15use crate::ln::channelmanager::{BlindedFailure, BlindedForward, CLTV_FAR_FAR_AWAY, HTLCFailureMsg, MIN_CLTV_EXPIRY_DELTA, PendingHTLCInfo, PendingHTLCRouting};
16use crate::types::features::BlindedHopFeatures;
17use crate::ln::msgs;
18use crate::ln::onion_utils;
19use crate::ln::onion_utils::{HTLCFailReason, INVALID_ONION_BLINDING};
20use crate::sign::{NodeSigner, Recipient};
21use crate::util::logger::Logger;
22
23#[allow(unused_imports)]
24use crate::prelude::*;
25
26use core::ops::Deref;
27
28#[derive(Clone, Debug, Hash, PartialEq, Eq)]
30pub struct InboundHTLCErr {
31 pub err_code: u16,
33 pub err_data: Vec<u8>,
35 pub msg: &'static str,
37}
38
39fn check_blinded_payment_constraints(
40 amt_msat: u64, cltv_expiry: u32, constraints: &PaymentConstraints
41) -> Result<(), ()> {
42 if amt_msat < constraints.htlc_minimum_msat ||
43 cltv_expiry > constraints.max_cltv_expiry
44 { return Err(()) }
45 Ok(())
46}
47
48fn check_blinded_forward(
49 inbound_amt_msat: u64, inbound_cltv_expiry: u32, payment_relay: &PaymentRelay,
50 payment_constraints: &PaymentConstraints, features: &BlindedHopFeatures
51) -> Result<(u64, u32), ()> {
52 let amt_to_forward = blinded_path::payment::amt_to_forward_msat(
53 inbound_amt_msat, payment_relay
54 ).ok_or(())?;
55 let outgoing_cltv_value = inbound_cltv_expiry.checked_sub(
56 payment_relay.cltv_expiry_delta as u32
57 ).ok_or(())?;
58 check_blinded_payment_constraints(inbound_amt_msat, outgoing_cltv_value, payment_constraints)?;
59
60 if features.requires_unknown_bits_from(&BlindedHopFeatures::empty()) { return Err(()) }
61 Ok((amt_to_forward, outgoing_cltv_value))
62}
63
64pub(super) fn create_fwd_pending_htlc_info(
65 msg: &msgs::UpdateAddHTLC, hop_data: msgs::InboundOnionPayload, hop_hmac: [u8; 32],
66 new_packet_bytes: [u8; onion_utils::ONION_DATA_LEN], shared_secret: [u8; 32],
67 next_packet_pubkey_opt: Option<Result<PublicKey, secp256k1::Error>>
68) -> Result<PendingHTLCInfo, InboundHTLCErr> {
69 debug_assert!(next_packet_pubkey_opt.is_some());
70 let outgoing_packet = msgs::OnionPacket {
71 version: 0,
72 public_key: next_packet_pubkey_opt.unwrap_or(Err(secp256k1::Error::InvalidPublicKey)),
73 hop_data: new_packet_bytes,
74 hmac: hop_hmac,
75 };
76
77 let (
78 short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point,
79 next_blinding_override
80 ) = match hop_data {
81 msgs::InboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } =>
82 (short_channel_id, amt_to_forward, outgoing_cltv_value, None, None),
83 msgs::InboundOnionPayload::BlindedForward {
84 short_channel_id, payment_relay, payment_constraints, intro_node_blinding_point, features,
85 next_blinding_override,
86 } => {
87 let (amt_to_forward, outgoing_cltv_value) = check_blinded_forward(
88 msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features
89 ).map_err(|()| {
90 InboundHTLCErr {
93 msg: "Underflow calculating outbound amount or cltv value for blinded forward",
94 err_code: INVALID_ONION_BLINDING,
95 err_data: vec![0; 32],
96 }
97 })?;
98 (short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point,
99 next_blinding_override)
100 },
101 msgs::InboundOnionPayload::Receive { .. } | msgs::InboundOnionPayload::BlindedReceive { .. } =>
102 return Err(InboundHTLCErr {
103 msg: "Final Node OnionHopData provided for us as an intermediary node",
104 err_code: 0x4000 | 22,
105 err_data: Vec::new(),
106 }),
107 };
108
109 Ok(PendingHTLCInfo {
110 routing: PendingHTLCRouting::Forward {
111 onion_packet: outgoing_packet,
112 short_channel_id,
113 incoming_cltv_expiry: Some(msg.cltv_expiry),
114 blinded: intro_node_blinding_point.or(msg.blinding_point)
115 .map(|bp| BlindedForward {
116 inbound_blinding_point: bp,
117 next_blinding_override,
118 failure: intro_node_blinding_point
119 .map(|_| BlindedFailure::FromIntroductionNode)
120 .unwrap_or(BlindedFailure::FromBlindedNode),
121 }),
122 },
123 payment_hash: msg.payment_hash,
124 incoming_shared_secret: shared_secret,
125 incoming_amt_msat: Some(msg.amount_msat),
126 outgoing_amt_msat: amt_to_forward,
127 outgoing_cltv_value,
128 skimmed_fee_msat: None,
129 })
130}
131
132pub(super) fn create_recv_pending_htlc_info(
133 hop_data: msgs::InboundOnionPayload, shared_secret: [u8; 32], payment_hash: PaymentHash,
134 amt_msat: u64, cltv_expiry: u32, phantom_shared_secret: Option<[u8; 32]>, allow_underpay: bool,
135 counterparty_skimmed_fee_msat: Option<u64>, current_height: u32
136) -> Result<PendingHTLCInfo, InboundHTLCErr> {
137 let (
138 payment_data, keysend_preimage, custom_tlvs, onion_amt_msat, onion_cltv_expiry,
139 payment_metadata, payment_context, requires_blinded_error, has_recipient_created_payment_secret
140 ) = match hop_data {
141 msgs::InboundOnionPayload::Receive {
142 payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
143 cltv_expiry_height, payment_metadata, ..
144 } =>
145 (payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
146 cltv_expiry_height, payment_metadata, None, false, keysend_preimage.is_none()),
147 msgs::InboundOnionPayload::BlindedReceive {
148 sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, payment_secret,
149 intro_node_blinding_point, payment_constraints, payment_context, keysend_preimage,
150 custom_tlvs
151 } => {
152 check_blinded_payment_constraints(
153 sender_intended_htlc_amt_msat, cltv_expiry, &payment_constraints
154 )
155 .map_err(|()| {
156 InboundHTLCErr {
157 err_code: INVALID_ONION_BLINDING,
158 err_data: vec![0; 32],
159 msg: "Amount or cltv_expiry violated blinded payment constraints",
160 }
161 })?;
162 let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat };
163 (Some(payment_data), keysend_preimage, custom_tlvs,
164 sender_intended_htlc_amt_msat, cltv_expiry_height, None, Some(payment_context),
165 intro_node_blinding_point.is_none(), true)
166 }
167 msgs::InboundOnionPayload::Forward { .. } => {
168 return Err(InboundHTLCErr {
169 err_code: 0x4000|22,
170 err_data: Vec::new(),
171 msg: "Got non final data with an HMAC of 0",
172 })
173 },
174 msgs::InboundOnionPayload::BlindedForward { .. } => {
175 return Err(InboundHTLCErr {
176 err_code: INVALID_ONION_BLINDING,
177 err_data: vec![0; 32],
178 msg: "Got blinded non final data with an HMAC of 0",
179 })
180 }
181 };
182 if onion_cltv_expiry > cltv_expiry {
184 return Err(InboundHTLCErr {
185 msg: "Upstream node set CLTV to less than the CLTV set by the sender",
186 err_code: 18,
187 err_data: cltv_expiry.to_be_bytes().to_vec()
188 })
189 }
190 if cltv_expiry <= current_height + HTLC_FAIL_BACK_BUFFER + 1 {
198 let mut err_data = Vec::with_capacity(12);
199 err_data.extend_from_slice(&amt_msat.to_be_bytes());
200 err_data.extend_from_slice(¤t_height.to_be_bytes());
201 return Err(InboundHTLCErr {
202 err_code: 0x4000 | 15, err_data,
203 msg: "The final CLTV expiry is too soon to handle",
204 });
205 }
206 if (!allow_underpay && onion_amt_msat > amt_msat) ||
207 (allow_underpay && onion_amt_msat >
208 amt_msat.saturating_add(counterparty_skimmed_fee_msat.unwrap_or(0)))
209 {
210 return Err(InboundHTLCErr {
211 err_code: 19,
212 err_data: amt_msat.to_be_bytes().to_vec(),
213 msg: "Upstream node sent less than we were supposed to receive in payment",
214 });
215 }
216
217 let routing = if let Some(payment_preimage) = keysend_preimage {
218 let hashed_preimage = PaymentHash(Sha256::hash(&payment_preimage.0).to_byte_array());
224 if hashed_preimage != payment_hash {
225 return Err(InboundHTLCErr {
226 err_code: 0x4000|22,
227 err_data: Vec::new(),
228 msg: "Payment preimage didn't match payment hash",
229 });
230 }
231 PendingHTLCRouting::ReceiveKeysend {
232 payment_data,
233 payment_preimage,
234 payment_metadata,
235 incoming_cltv_expiry: onion_cltv_expiry,
236 custom_tlvs,
237 requires_blinded_error,
238 has_recipient_created_payment_secret,
239 }
240 } else if let Some(data) = payment_data {
241 PendingHTLCRouting::Receive {
242 payment_data: data,
243 payment_metadata,
244 payment_context,
245 incoming_cltv_expiry: onion_cltv_expiry,
246 phantom_shared_secret,
247 custom_tlvs,
248 requires_blinded_error,
249 }
250 } else {
251 return Err(InboundHTLCErr {
252 err_code: 0x4000|0x2000|3,
253 err_data: Vec::new(),
254 msg: "We require payment_secrets",
255 });
256 };
257 Ok(PendingHTLCInfo {
258 routing,
259 payment_hash,
260 incoming_shared_secret: shared_secret,
261 incoming_amt_msat: Some(amt_msat),
262 outgoing_amt_msat: onion_amt_msat,
263 outgoing_cltv_value: onion_cltv_expiry,
264 skimmed_fee_msat: counterparty_skimmed_fee_msat,
265 })
266}
267
268pub fn peel_payment_onion<NS: Deref, L: Deref, T: secp256k1::Verification>(
278 msg: &msgs::UpdateAddHTLC, node_signer: NS, logger: L, secp_ctx: &Secp256k1<T>,
279 cur_height: u32, allow_skimmed_fees: bool,
280) -> Result<PendingHTLCInfo, InboundHTLCErr>
281where
282 NS::Target: NodeSigner,
283 L::Target: Logger,
284{
285 let (hop, shared_secret, next_packet_details_opt) =
286 decode_incoming_update_add_htlc_onion(msg, node_signer, logger, secp_ctx
287 ).map_err(|e| {
288 let (err_code, err_data) = match e {
289 HTLCFailureMsg::Malformed(m) => (m.failure_code, Vec::new()),
290 HTLCFailureMsg::Relay(r) => (0x4000 | 22, r.reason.data),
291 };
292 let msg = "Failed to decode update add htlc onion";
293 InboundHTLCErr { msg, err_code, err_data }
294 })?;
295 Ok(match hop {
296 onion_utils::Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes } => {
297 let NextPacketDetails {
298 next_packet_pubkey, outgoing_amt_msat: _, outgoing_scid: _, outgoing_cltv_value
299 } = match next_packet_details_opt {
300 Some(next_packet_details) => next_packet_details,
301 None => return Err(InboundHTLCErr {
303 msg: "Failed to decode update add htlc onion",
304 err_code: 0x4000 | 22,
305 err_data: Vec::new(),
306 }),
307 };
308
309 if let Err((err_msg, code)) = check_incoming_htlc_cltv(
310 cur_height, outgoing_cltv_value, msg.cltv_expiry
311 ) {
312 return Err(InboundHTLCErr {
313 msg: err_msg,
314 err_code: code,
315 err_data: Vec::new(),
316 });
317 }
318
319 create_fwd_pending_htlc_info(
323 msg, next_hop_data, next_hop_hmac, new_packet_bytes, shared_secret,
324 Some(next_packet_pubkey)
325 )?
326 },
327 onion_utils::Hop::Receive(received_data) => {
328 create_recv_pending_htlc_info(
329 received_data, shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry,
330 None, allow_skimmed_fees, msg.skimmed_fee_msat, cur_height
331 )?
332 }
333 })
334}
335
336pub(super) struct NextPacketDetails {
337 pub(super) next_packet_pubkey: Result<PublicKey, secp256k1::Error>,
338 pub(super) outgoing_scid: u64,
339 pub(super) outgoing_amt_msat: u64,
340 pub(super) outgoing_cltv_value: u32,
341}
342
343pub(super) fn decode_incoming_update_add_htlc_onion<NS: Deref, L: Deref, T: secp256k1::Verification>(
344 msg: &msgs::UpdateAddHTLC, node_signer: NS, logger: L, secp_ctx: &Secp256k1<T>,
345) -> Result<(onion_utils::Hop, [u8; 32], Option<NextPacketDetails>), HTLCFailureMsg>
346where
347 NS::Target: NodeSigner,
348 L::Target: Logger,
349{
350 macro_rules! return_malformed_err {
351 ($msg: expr, $err_code: expr) => {
352 {
353 log_info!(logger, "Failed to accept/forward incoming HTLC: {}", $msg);
354 let (sha256_of_onion, failure_code) = if msg.blinding_point.is_some() {
355 ([0; 32], INVALID_ONION_BLINDING)
356 } else {
357 (Sha256::hash(&msg.onion_routing_packet.hop_data).to_byte_array(), $err_code)
358 };
359 return Err(HTLCFailureMsg::Malformed(msgs::UpdateFailMalformedHTLC {
360 channel_id: msg.channel_id,
361 htlc_id: msg.htlc_id,
362 sha256_of_onion,
363 failure_code,
364 }));
365 }
366 }
367 }
368
369 if let Err(_) = msg.onion_routing_packet.public_key {
370 return_malformed_err!("invalid ephemeral pubkey", 0x8000 | 0x4000 | 6);
371 }
372
373 let blinded_node_id_tweak = msg.blinding_point.map(|bp| {
374 let blinded_tlvs_ss = node_signer.ecdh(Recipient::Node, &bp, None).unwrap().secret_bytes();
375 let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
376 hmac.input(blinded_tlvs_ss.as_ref());
377 Scalar::from_be_bytes(Hmac::from_engine(hmac).to_byte_array()).unwrap()
378 });
379 let shared_secret = node_signer.ecdh(
380 Recipient::Node, &msg.onion_routing_packet.public_key.unwrap(), blinded_node_id_tweak.as_ref()
381 ).unwrap().secret_bytes();
382
383 if msg.onion_routing_packet.version != 0 {
384 return_malformed_err!("Unknown onion packet version", 0x8000 | 0x4000 | 4);
391 }
392 macro_rules! return_err {
393 ($msg: expr, $err_code: expr, $data: expr) => {
394 {
395 if msg.blinding_point.is_some() {
396 return_malformed_err!($msg, INVALID_ONION_BLINDING)
397 }
398
399 log_info!(logger, "Failed to accept/forward incoming HTLC: {}", $msg);
400 return Err(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC {
401 channel_id: msg.channel_id,
402 htlc_id: msg.htlc_id,
403 reason: HTLCFailReason::reason($err_code, $data.to_vec())
404 .get_encrypted_failure_packet(&shared_secret, &None),
405 }));
406 }
407 }
408 }
409
410 let next_hop = match onion_utils::decode_next_payment_hop(
411 shared_secret, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac,
412 msg.payment_hash, msg.blinding_point, node_signer
413 ) {
414 Ok(res) => res,
415 Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {
416 return_malformed_err!(err_msg, err_code);
417 },
418 Err(onion_utils::OnionDecodeErr::Relay { err_msg, err_code }) => {
419 return_err!(err_msg, err_code, &[0; 0]);
420 },
421 };
422
423 let next_packet_details = match next_hop {
424 onion_utils::Hop::Forward {
425 next_hop_data: msgs::InboundOnionPayload::Forward {
426 short_channel_id, amt_to_forward, outgoing_cltv_value
427 }, ..
428 } => {
429 let next_packet_pubkey = onion_utils::next_hop_pubkey(secp_ctx,
430 msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
431 NextPacketDetails {
432 next_packet_pubkey, outgoing_scid: short_channel_id,
433 outgoing_amt_msat: amt_to_forward, outgoing_cltv_value
434 }
435 },
436 onion_utils::Hop::Forward {
437 next_hop_data: msgs::InboundOnionPayload::BlindedForward {
438 short_channel_id, ref payment_relay, ref payment_constraints, ref features, ..
439 }, ..
440 } => {
441 let (amt_to_forward, outgoing_cltv_value) = match check_blinded_forward(
442 msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features
443 ) {
444 Ok((amt, cltv)) => (amt, cltv),
445 Err(()) => {
446 return_err!("Underflow calculating outbound amount or cltv value for blinded forward",
447 INVALID_ONION_BLINDING, &[0; 32]);
448 }
449 };
450 let next_packet_pubkey = onion_utils::next_hop_pubkey(&secp_ctx,
451 msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
452 NextPacketDetails {
453 next_packet_pubkey, outgoing_scid: short_channel_id, outgoing_amt_msat: amt_to_forward,
454 outgoing_cltv_value
455 }
456 },
457 onion_utils::Hop::Receive { .. } => return Ok((next_hop, shared_secret, None)),
458 onion_utils::Hop::Forward { next_hop_data: msgs::InboundOnionPayload::Receive { .. }, .. } |
459 onion_utils::Hop::Forward { next_hop_data: msgs::InboundOnionPayload::BlindedReceive { .. }, .. } =>
460 {
461 return_err!("Final Node OnionHopData provided for us as an intermediary node", 0x4000 | 22, &[0; 0]);
462 }
463 };
464
465 Ok((next_hop, shared_secret, Some(next_packet_details)))
466}
467
468pub(super) fn check_incoming_htlc_cltv(
469 cur_height: u32, outgoing_cltv_value: u32, cltv_expiry: u32
470) -> Result<(), (&'static str, u16)> {
471 if (cltv_expiry as u64) < (outgoing_cltv_value) as u64 + MIN_CLTV_EXPIRY_DELTA as u64 {
472 return Err((
473 "Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta",
474 0x1000 | 13, ));
476 }
477 if cltv_expiry <= cur_height + HTLC_FAIL_BACK_BUFFER as u32 { return Err(("CLTV expiry is too close", 0x1000 | 14));
482 }
483 if cltv_expiry > cur_height + CLTV_FAR_FAR_AWAY as u32 { return Err(("CLTV expiry is too far in the future", 21));
485 }
486 if (outgoing_cltv_value) as u64 <= (cur_height + LATENCY_GRACE_PERIOD_BLOCKS) as u64 {
495 return Err(("Outgoing CLTV value is too soon", 0x1000 | 14));
496 }
497
498 Ok(())
499}
500
501#[cfg(test)]
502mod tests {
503 use bitcoin::hashes::Hash;
504 use bitcoin::hashes::sha256::Hash as Sha256;
505 use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
506 use crate::ln::types::ChannelId;
507 use crate::types::payment::{PaymentPreimage, PaymentHash, PaymentSecret};
508 use crate::ln::channelmanager::RecipientOnionFields;
509 use crate::types::features::{ChannelFeatures, NodeFeatures};
510 use crate::ln::msgs;
511 use crate::ln::onion_utils::create_payment_onion;
512 use crate::routing::router::{Path, RouteHop};
513 use crate::util::test_utils;
514
515 #[test]
516 fn fail_construct_onion_on_too_big_payloads() {
517 let secp_ctx = Secp256k1::new();
523 let bob = crate::sign::KeysManager::new(&[2; 32], 42, 42);
524 let bob_pk = PublicKey::from_secret_key(&secp_ctx, &bob.get_node_secret_key());
525 let charlie = crate::sign::KeysManager::new(&[3; 32], 42, 42);
526 let charlie_pk = PublicKey::from_secret_key(&secp_ctx, &charlie.get_node_secret_key());
527
528 let (
529 session_priv, total_amt_msat, cur_height, mut recipient_onion, keysend_preimage, payment_hash,
530 prng_seed, hops, ..
531 ) = payment_onion_args(bob_pk, charlie_pk);
532
533 recipient_onion.custom_tlvs.push((13377331, vec![0; 1156]));
535
536 let path = Path { hops, blinded_tail: None, };
537 let onion_keys = super::onion_utils::construct_onion_keys(&secp_ctx, &path, &session_priv).unwrap();
538 let (onion_payloads, ..) = super::onion_utils::build_onion_payloads(
539 &path, total_amt_msat, &recipient_onion, cur_height + 1, &Some(keysend_preimage), None
540 ).unwrap();
541
542 assert!(super::onion_utils::construct_onion_packet(
543 onion_payloads, onion_keys, prng_seed, &payment_hash
544 ).is_err());
545 }
546
547 #[test]
548 fn test_peel_payment_onion() {
549 use super::*;
550 let secp_ctx = Secp256k1::new();
551
552 let bob = crate::sign::KeysManager::new(&[2; 32], 42, 42);
553 let bob_pk = PublicKey::from_secret_key(&secp_ctx, &bob.get_node_secret_key());
554 let charlie = crate::sign::KeysManager::new(&[3; 32], 42, 42);
555 let charlie_pk = PublicKey::from_secret_key(&secp_ctx, &charlie.get_node_secret_key());
556
557 let (session_priv, total_amt_msat, cur_height, recipient_onion, preimage, payment_hash,
558 prng_seed, hops, recipient_amount, pay_secret) = payment_onion_args(bob_pk, charlie_pk);
559
560 let path = Path {
561 hops: hops,
562 blinded_tail: None,
563 };
564
565 let (onion, amount_msat, cltv_expiry) = create_payment_onion(
566 &secp_ctx, &path, &session_priv, total_amt_msat, &recipient_onion,
567 cur_height, &payment_hash, &Some(preimage), None, prng_seed
568 ).unwrap();
569
570 let msg = make_update_add_msg(amount_msat, cltv_expiry, payment_hash, onion);
571 let logger = test_utils::TestLogger::with_id("bob".to_string());
572
573 let peeled = peel_payment_onion(&msg, &bob, &logger, &secp_ctx, cur_height, false)
574 .map_err(|e| e.msg).unwrap();
575
576 let next_onion = match peeled.routing {
577 PendingHTLCRouting::Forward { onion_packet, .. } => {
578 onion_packet
579 },
580 _ => panic!("expected a forwarded onion"),
581 };
582
583 let msg2 = make_update_add_msg(amount_msat, cltv_expiry, payment_hash, next_onion);
584 let peeled2 = peel_payment_onion(&msg2, &charlie, &logger, &secp_ctx, cur_height, false)
585 .map_err(|e| e.msg).unwrap();
586
587 match peeled2.routing {
588 PendingHTLCRouting::ReceiveKeysend { payment_preimage, payment_data, incoming_cltv_expiry, .. } => {
589 assert_eq!(payment_preimage, preimage);
590 assert_eq!(peeled2.outgoing_amt_msat, recipient_amount);
591 assert_eq!(incoming_cltv_expiry, peeled2.outgoing_cltv_value);
592 let msgs::FinalOnionHopData{total_msat, payment_secret} = payment_data.unwrap();
593 assert_eq!(total_msat, total_amt_msat);
594 assert_eq!(payment_secret, pay_secret);
595 },
596 _ => panic!("expected a received keysend"),
597 };
598 }
599
600 fn make_update_add_msg(
601 amount_msat: u64, cltv_expiry: u32, payment_hash: PaymentHash,
602 onion_routing_packet: msgs::OnionPacket
603 ) -> msgs::UpdateAddHTLC {
604 msgs::UpdateAddHTLC {
605 channel_id: ChannelId::from_bytes([0; 32]),
606 htlc_id: 0,
607 amount_msat,
608 cltv_expiry,
609 payment_hash,
610 onion_routing_packet,
611 skimmed_fee_msat: None,
612 blinding_point: None,
613 }
614 }
615
616 fn payment_onion_args(hop_pk: PublicKey, recipient_pk: PublicKey) -> (
617 SecretKey, u64, u32, RecipientOnionFields, PaymentPreimage, PaymentHash, [u8; 32],
618 Vec<RouteHop>, u64, PaymentSecret,
619 ) {
620 let session_priv_bytes = [42; 32];
621 let session_priv = SecretKey::from_slice(&session_priv_bytes).unwrap();
622 let total_amt_msat = 1000;
623 let cur_height = 1000;
624 let pay_secret = PaymentSecret([99; 32]);
625 let recipient_onion = RecipientOnionFields::secret_only(pay_secret);
626 let preimage_bytes = [43; 32];
627 let preimage = PaymentPreimage(preimage_bytes);
628 let rhash_bytes = Sha256::hash(&preimage_bytes).to_byte_array();
629 let payment_hash = PaymentHash(rhash_bytes);
630 let prng_seed = [44; 32];
631
632 let hop_fee = 1;
634 let recipient_amount = total_amt_msat - hop_fee;
635 let hops = vec![
636 RouteHop {
637 pubkey: hop_pk,
638 fee_msat: hop_fee,
639 cltv_expiry_delta: 42,
640 short_channel_id: 1,
641 node_features: NodeFeatures::empty(),
642 channel_features: ChannelFeatures::empty(),
643 maybe_announced_channel: false,
644 },
645 RouteHop {
646 pubkey: recipient_pk,
647 fee_msat: recipient_amount,
648 cltv_expiry_delta: 42,
649 short_channel_id: 2,
650 node_features: NodeFeatures::empty(),
651 channel_features: ChannelFeatures::empty(),
652 maybe_announced_channel: false,
653 }
654 ];
655
656 (session_priv, total_amt_msat, cur_height, recipient_onion, preimage, payment_hash,
657 prng_seed, hops, recipient_amount, pay_secret)
658 }
659
660}