]> git.bitcoin.ninja Git - rust-lightning/blob - lightning/src/ln/onion_payment.rs
Add redundant blinded HTLC failure check for posterity.
[rust-lightning] / lightning / src / ln / onion_payment.rs
1 //! Utilities to decode payment onions and do contextless validation of incoming payments.
2 //!
3 //! Primarily features [`peel_payment_onion`], which allows the decoding of an onion statelessly
4 //! and can be used to predict whether we'd accept a payment.
5
6 use bitcoin::hashes::{Hash, HashEngine};
7 use bitcoin::hashes::hmac::{Hmac, HmacEngine};
8 use bitcoin::hashes::sha256::Hash as Sha256;
9 use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1};
10
11 use crate::blinded_path;
12 use crate::blinded_path::payment::{PaymentConstraints, PaymentRelay};
13 use crate::chain::channelmonitor::{HTLC_FAIL_BACK_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS};
14 use crate::ln::PaymentHash;
15 use crate::ln::channelmanager::{BlindedForward, CLTV_FAR_FAR_AWAY, HTLCFailureMsg, MIN_CLTV_EXPIRY_DELTA, PendingHTLCInfo, PendingHTLCRouting};
16 use crate::ln::features::BlindedHopFeatures;
17 use crate::ln::msgs;
18 use crate::ln::onion_utils;
19 use crate::ln::onion_utils::{HTLCFailReason, INVALID_ONION_BLINDING};
20 use crate::sign::{NodeSigner, Recipient};
21 use crate::util::logger::Logger;
22
23 use crate::prelude::*;
24 use core::ops::Deref;
25
26 /// Invalid inbound onion payment.
27 pub struct InboundOnionErr {
28         /// BOLT 4 error code.
29         pub err_code: u16,
30         /// Data attached to this error.
31         pub err_data: Vec<u8>,
32         /// Error message text.
33         pub msg: &'static str,
34 }
35
36 fn check_blinded_payment_constraints(
37         amt_msat: u64, cltv_expiry: u32, constraints: &PaymentConstraints
38 ) -> Result<(), ()> {
39         if amt_msat < constraints.htlc_minimum_msat ||
40                 cltv_expiry > constraints.max_cltv_expiry
41         { return Err(()) }
42         Ok(())
43 }
44
45 fn check_blinded_forward(
46         inbound_amt_msat: u64, inbound_cltv_expiry: u32, payment_relay: &PaymentRelay,
47         payment_constraints: &PaymentConstraints, features: &BlindedHopFeatures
48 ) -> Result<(u64, u32), ()> {
49         let amt_to_forward = blinded_path::payment::amt_to_forward_msat(
50                 inbound_amt_msat, payment_relay
51         ).ok_or(())?;
52         let outgoing_cltv_value = inbound_cltv_expiry.checked_sub(
53                 payment_relay.cltv_expiry_delta as u32
54         ).ok_or(())?;
55         check_blinded_payment_constraints(inbound_amt_msat, outgoing_cltv_value, payment_constraints)?;
56
57         if features.requires_unknown_bits_from(&BlindedHopFeatures::empty()) { return Err(()) }
58         Ok((amt_to_forward, outgoing_cltv_value))
59 }
60
61 pub(super) fn create_fwd_pending_htlc_info(
62         msg: &msgs::UpdateAddHTLC, hop_data: msgs::InboundOnionPayload, hop_hmac: [u8; 32],
63         new_packet_bytes: [u8; onion_utils::ONION_DATA_LEN], shared_secret: [u8; 32],
64         next_packet_pubkey_opt: Option<Result<PublicKey, secp256k1::Error>>
65 ) -> Result<PendingHTLCInfo, InboundOnionErr> {
66         debug_assert!(next_packet_pubkey_opt.is_some());
67         let outgoing_packet = msgs::OnionPacket {
68                 version: 0,
69                 public_key: next_packet_pubkey_opt.unwrap_or(Err(secp256k1::Error::InvalidPublicKey)),
70                 hop_data: new_packet_bytes,
71                 hmac: hop_hmac,
72         };
73
74         let (
75                 short_channel_id, amt_to_forward, outgoing_cltv_value, inbound_blinding_point
76         ) = match hop_data {
77                 msgs::InboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } =>
78                         (short_channel_id, amt_to_forward, outgoing_cltv_value, None),
79                 msgs::InboundOnionPayload::BlindedForward {
80                         short_channel_id, payment_relay, payment_constraints, intro_node_blinding_point, features,
81                 } => {
82                         let (amt_to_forward, outgoing_cltv_value) = check_blinded_forward(
83                                 msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features
84                         ).map_err(|()| {
85                                 // We should be returning malformed here if `msg.blinding_point` is set, but this is
86                                 // unreachable right now since we checked it in `decode_update_add_htlc_onion`.
87                                 InboundOnionErr {
88                                         msg: "Underflow calculating outbound amount or cltv value for blinded forward",
89                                         err_code: INVALID_ONION_BLINDING,
90                                         err_data: vec![0; 32],
91                                 }
92                         })?;
93                         (short_channel_id, amt_to_forward, outgoing_cltv_value, Some(intro_node_blinding_point))
94                 },
95                 msgs::InboundOnionPayload::Receive { .. } | msgs::InboundOnionPayload::BlindedReceive { .. } =>
96                         return Err(InboundOnionErr {
97                                 msg: "Final Node OnionHopData provided for us as an intermediary node",
98                                 err_code: 0x4000 | 22,
99                                 err_data: Vec::new(),
100                         }),
101         };
102
103         Ok(PendingHTLCInfo {
104                 routing: PendingHTLCRouting::Forward {
105                         onion_packet: outgoing_packet,
106                         short_channel_id,
107                         blinded: inbound_blinding_point.map(|bp| BlindedForward { inbound_blinding_point: bp }),
108                 },
109                 payment_hash: msg.payment_hash,
110                 incoming_shared_secret: shared_secret,
111                 incoming_amt_msat: Some(msg.amount_msat),
112                 outgoing_amt_msat: amt_to_forward,
113                 outgoing_cltv_value,
114                 skimmed_fee_msat: None,
115         })
116 }
117
118 pub(super) fn create_recv_pending_htlc_info(
119         hop_data: msgs::InboundOnionPayload, shared_secret: [u8; 32], payment_hash: PaymentHash,
120         amt_msat: u64, cltv_expiry: u32, phantom_shared_secret: Option<[u8; 32]>, allow_underpay: bool,
121         counterparty_skimmed_fee_msat: Option<u64>, current_height: u32, accept_mpp_keysend: bool,
122 ) -> Result<PendingHTLCInfo, InboundOnionErr> {
123         let (
124                 payment_data, keysend_preimage, custom_tlvs, onion_amt_msat, outgoing_cltv_value,
125                 payment_metadata, requires_blinded_error
126         ) = match hop_data {
127                 msgs::InboundOnionPayload::Receive {
128                         payment_data, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value, payment_metadata, ..
129                 } =>
130                         (payment_data, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value, payment_metadata,
131                          false),
132                 msgs::InboundOnionPayload::BlindedReceive {
133                         amt_msat, total_msat, outgoing_cltv_value, payment_secret, intro_node_blinding_point,
134                         payment_constraints, ..
135                 } => {
136                         check_blinded_payment_constraints(amt_msat, cltv_expiry, &payment_constraints)
137                                 .map_err(|()| {
138                                         InboundOnionErr {
139                                                 err_code: INVALID_ONION_BLINDING,
140                                                 err_data: vec![0; 32],
141                                                 msg: "Amount or cltv_expiry violated blinded payment constraints",
142                                         }
143                                 })?;
144                         let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat };
145                         (Some(payment_data), None, Vec::new(), amt_msat, outgoing_cltv_value, None,
146                          intro_node_blinding_point.is_none())
147                 }
148                 msgs::InboundOnionPayload::Forward { .. } => {
149                         return Err(InboundOnionErr {
150                                 err_code: 0x4000|22,
151                                 err_data: Vec::new(),
152                                 msg: "Got non final data with an HMAC of 0",
153                         })
154                 },
155                 msgs::InboundOnionPayload::BlindedForward { .. } => {
156                         return Err(InboundOnionErr {
157                                 err_code: INVALID_ONION_BLINDING,
158                                 err_data: vec![0; 32],
159                                 msg: "Got blinded non final data with an HMAC of 0",
160                         })
161                 }
162         };
163         // final_incorrect_cltv_expiry
164         if outgoing_cltv_value > cltv_expiry {
165                 return Err(InboundOnionErr {
166                         msg: "Upstream node set CLTV to less than the CLTV set by the sender",
167                         err_code: 18,
168                         err_data: cltv_expiry.to_be_bytes().to_vec()
169                 })
170         }
171         // final_expiry_too_soon
172         // We have to have some headroom to broadcast on chain if we have the preimage, so make sure
173         // we have at least HTLC_FAIL_BACK_BUFFER blocks to go.
174         //
175         // Also, ensure that, in the case of an unknown preimage for the received payment hash, our
176         // payment logic has enough time to fail the HTLC backward before our onchain logic triggers a
177         // channel closure (see HTLC_FAIL_BACK_BUFFER rationale).
178         if cltv_expiry <= current_height + HTLC_FAIL_BACK_BUFFER + 1 {
179                 let mut err_data = Vec::with_capacity(12);
180                 err_data.extend_from_slice(&amt_msat.to_be_bytes());
181                 err_data.extend_from_slice(&current_height.to_be_bytes());
182                 return Err(InboundOnionErr {
183                         err_code: 0x4000 | 15, err_data,
184                         msg: "The final CLTV expiry is too soon to handle",
185                 });
186         }
187         if (!allow_underpay && onion_amt_msat > amt_msat) ||
188                 (allow_underpay && onion_amt_msat >
189                  amt_msat.saturating_add(counterparty_skimmed_fee_msat.unwrap_or(0)))
190         {
191                 return Err(InboundOnionErr {
192                         err_code: 19,
193                         err_data: amt_msat.to_be_bytes().to_vec(),
194                         msg: "Upstream node sent less than we were supposed to receive in payment",
195                 });
196         }
197
198         let routing = if let Some(payment_preimage) = keysend_preimage {
199                 // We need to check that the sender knows the keysend preimage before processing this
200                 // payment further. Otherwise, an intermediary routing hop forwarding non-keysend-HTLC X
201                 // could discover the final destination of X, by probing the adjacent nodes on the route
202                 // with a keysend payment of identical payment hash to X and observing the processing
203                 // time discrepancies due to a hash collision with X.
204                 let hashed_preimage = PaymentHash(Sha256::hash(&payment_preimage.0).to_byte_array());
205                 if hashed_preimage != payment_hash {
206                         return Err(InboundOnionErr {
207                                 err_code: 0x4000|22,
208                                 err_data: Vec::new(),
209                                 msg: "Payment preimage didn't match payment hash",
210                         });
211                 }
212                 if !accept_mpp_keysend && payment_data.is_some() {
213                         return Err(InboundOnionErr {
214                                 err_code: 0x4000|22,
215                                 err_data: Vec::new(),
216                                 msg: "We don't support MPP keysend payments",
217                         });
218                 }
219                 PendingHTLCRouting::ReceiveKeysend {
220                         payment_data,
221                         payment_preimage,
222                         payment_metadata,
223                         incoming_cltv_expiry: outgoing_cltv_value,
224                         custom_tlvs,
225                 }
226         } else if let Some(data) = payment_data {
227                 PendingHTLCRouting::Receive {
228                         payment_data: data,
229                         payment_metadata,
230                         incoming_cltv_expiry: outgoing_cltv_value,
231                         phantom_shared_secret,
232                         custom_tlvs,
233                         requires_blinded_error,
234                 }
235         } else {
236                 return Err(InboundOnionErr {
237                         err_code: 0x4000|0x2000|3,
238                         err_data: Vec::new(),
239                         msg: "We require payment_secrets",
240                 });
241         };
242         Ok(PendingHTLCInfo {
243                 routing,
244                 payment_hash,
245                 incoming_shared_secret: shared_secret,
246                 incoming_amt_msat: Some(amt_msat),
247                 outgoing_amt_msat: onion_amt_msat,
248                 outgoing_cltv_value,
249                 skimmed_fee_msat: counterparty_skimmed_fee_msat,
250         })
251 }
252
253 /// Peel one layer off an incoming onion, returning a [`PendingHTLCInfo`] that contains information
254 /// about the intended next-hop for the HTLC.
255 ///
256 /// This does all the relevant context-free checks that LDK requires for payment relay or
257 /// acceptance. If the payment is to be received, and the amount matches the expected amount for
258 /// a given invoice, this indicates the [`msgs::UpdateAddHTLC`], once fully committed in the
259 /// channel, will generate an [`Event::PaymentClaimable`].
260 ///
261 /// [`Event::PaymentClaimable`]: crate::events::Event::PaymentClaimable
262 pub fn peel_payment_onion<NS: Deref, L: Deref, T: secp256k1::Verification>(
263         msg: &msgs::UpdateAddHTLC, node_signer: &NS, logger: &L, secp_ctx: &Secp256k1<T>,
264         cur_height: u32, accept_mpp_keysend: bool, allow_skimmed_fees: bool,
265 ) -> Result<PendingHTLCInfo, InboundOnionErr>
266 where
267         NS::Target: NodeSigner,
268         L::Target: Logger,
269 {
270         let (hop, shared_secret, next_packet_details_opt) =
271                 decode_incoming_update_add_htlc_onion(msg, node_signer, logger, secp_ctx
272         ).map_err(|e| {
273                 let (err_code, err_data) = match e {
274                         HTLCFailureMsg::Malformed(m) => (m.failure_code, Vec::new()),
275                         HTLCFailureMsg::Relay(r) => (0x4000 | 22, r.reason.data),
276                 };
277                 let msg = "Failed to decode update add htlc onion";
278                 InboundOnionErr { msg, err_code, err_data }
279         })?;
280         Ok(match hop {
281                 onion_utils::Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes } => {
282                         let NextPacketDetails {
283                                 next_packet_pubkey, outgoing_amt_msat: _, outgoing_scid: _, outgoing_cltv_value
284                         } = match next_packet_details_opt {
285                                 Some(next_packet_details) => next_packet_details,
286                                 // Forward should always include the next hop details
287                                 None => return Err(InboundOnionErr {
288                                         msg: "Failed to decode update add htlc onion",
289                                         err_code: 0x4000 | 22,
290                                         err_data: Vec::new(),
291                                 }),
292                         };
293
294                         if let Err((err_msg, code)) = check_incoming_htlc_cltv(
295                                 cur_height, outgoing_cltv_value, msg.cltv_expiry
296                         ) {
297                                 return Err(InboundOnionErr {
298                                         msg: err_msg,
299                                         err_code: code,
300                                         err_data: Vec::new(),
301                                 });
302                         }
303
304                         // TODO: If this is potentially a phantom payment we should decode the phantom payment
305                         // onion here and check it.
306
307                         create_fwd_pending_htlc_info(
308                                 msg, next_hop_data, next_hop_hmac, new_packet_bytes, shared_secret,
309                                 Some(next_packet_pubkey)
310                         )?
311                 },
312                 onion_utils::Hop::Receive(received_data) => {
313                         create_recv_pending_htlc_info(
314                                 received_data, shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry,
315                                 None, allow_skimmed_fees, msg.skimmed_fee_msat, cur_height, accept_mpp_keysend,
316                         )?
317                 }
318         })
319 }
320
321 pub(super) struct NextPacketDetails {
322         pub(super) next_packet_pubkey: Result<PublicKey, secp256k1::Error>,
323         pub(super) outgoing_scid: u64,
324         pub(super) outgoing_amt_msat: u64,
325         pub(super) outgoing_cltv_value: u32,
326 }
327
328 pub(super) fn decode_incoming_update_add_htlc_onion<NS: Deref, L: Deref, T: secp256k1::Verification>(
329         msg: &msgs::UpdateAddHTLC, node_signer: &NS, logger: &L, secp_ctx: &Secp256k1<T>,
330 ) -> Result<(onion_utils::Hop, [u8; 32], Option<NextPacketDetails>), HTLCFailureMsg>
331 where
332         NS::Target: NodeSigner,
333         L::Target: Logger,
334 {
335         macro_rules! return_malformed_err {
336                 ($msg: expr, $err_code: expr) => {
337                         {
338                                 log_info!(logger, "Failed to accept/forward incoming HTLC: {}", $msg);
339                                 let (sha256_of_onion, failure_code) = if msg.blinding_point.is_some() {
340                                         ([0; 32], INVALID_ONION_BLINDING)
341                                 } else {
342                                         (Sha256::hash(&msg.onion_routing_packet.hop_data).to_byte_array(), $err_code)
343                                 };
344                                 return Err(HTLCFailureMsg::Malformed(msgs::UpdateFailMalformedHTLC {
345                                         channel_id: msg.channel_id,
346                                         htlc_id: msg.htlc_id,
347                                         sha256_of_onion,
348                                         failure_code,
349                                 }));
350                         }
351                 }
352         }
353
354         if let Err(_) = msg.onion_routing_packet.public_key {
355                 return_malformed_err!("invalid ephemeral pubkey", 0x8000 | 0x4000 | 6);
356         }
357
358         let blinded_node_id_tweak = msg.blinding_point.map(|bp| {
359                 let blinded_tlvs_ss = node_signer.ecdh(Recipient::Node, &bp, None).unwrap().secret_bytes();
360                 let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
361                 hmac.input(blinded_tlvs_ss.as_ref());
362                 Scalar::from_be_bytes(Hmac::from_engine(hmac).to_byte_array()).unwrap()
363         });
364         let shared_secret = node_signer.ecdh(
365                 Recipient::Node, &msg.onion_routing_packet.public_key.unwrap(), blinded_node_id_tweak.as_ref()
366         ).unwrap().secret_bytes();
367
368         if msg.onion_routing_packet.version != 0 {
369                 //TODO: Spec doesn't indicate if we should only hash hop_data here (and in other
370                 //sha256_of_onion error data packets), or the entire onion_routing_packet. Either way,
371                 //the hash doesn't really serve any purpose - in the case of hashing all data, the
372                 //receiving node would have to brute force to figure out which version was put in the
373                 //packet by the node that send us the message, in the case of hashing the hop_data, the
374                 //node knows the HMAC matched, so they already know what is there...
375                 return_malformed_err!("Unknown onion packet version", 0x8000 | 0x4000 | 4);
376         }
377         macro_rules! return_err {
378                 ($msg: expr, $err_code: expr, $data: expr) => {
379                         {
380                                 if msg.blinding_point.is_some() {
381                                         return_malformed_err!($msg, INVALID_ONION_BLINDING)
382                                 }
383
384                                 log_info!(logger, "Failed to accept/forward incoming HTLC: {}", $msg);
385                                 return Err(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC {
386                                         channel_id: msg.channel_id,
387                                         htlc_id: msg.htlc_id,
388                                         reason: HTLCFailReason::reason($err_code, $data.to_vec())
389                                                 .get_encrypted_failure_packet(&shared_secret, &None),
390                                 }));
391                         }
392                 }
393         }
394
395         let next_hop = match onion_utils::decode_next_payment_hop(
396                 shared_secret, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac,
397                 msg.payment_hash, msg.blinding_point, node_signer
398         ) {
399                 Ok(res) => res,
400                 Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {
401                         return_malformed_err!(err_msg, err_code);
402                 },
403                 Err(onion_utils::OnionDecodeErr::Relay { err_msg, err_code }) => {
404                         return_err!(err_msg, err_code, &[0; 0]);
405                 },
406         };
407
408         let next_packet_details = match next_hop {
409                 onion_utils::Hop::Forward {
410                         next_hop_data: msgs::InboundOnionPayload::Forward {
411                                 short_channel_id, amt_to_forward, outgoing_cltv_value
412                         }, ..
413                 } => {
414                         let next_packet_pubkey = onion_utils::next_hop_pubkey(secp_ctx,
415                                 msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
416                         NextPacketDetails {
417                                 next_packet_pubkey, outgoing_scid: short_channel_id,
418                                 outgoing_amt_msat: amt_to_forward, outgoing_cltv_value
419                         }
420                 },
421                 onion_utils::Hop::Forward {
422                         next_hop_data: msgs::InboundOnionPayload::BlindedForward {
423                                 short_channel_id, ref payment_relay, ref payment_constraints, ref features, ..
424                         }, ..
425                 } => {
426                         let (amt_to_forward, outgoing_cltv_value) = match check_blinded_forward(
427                                 msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features
428                         ) {
429                                 Ok((amt, cltv)) => (amt, cltv),
430                                 Err(()) => {
431                                         return_err!("Underflow calculating outbound amount or cltv value for blinded forward",
432                                                 INVALID_ONION_BLINDING, &[0; 32]);
433                                 }
434                         };
435                         let next_packet_pubkey = onion_utils::next_hop_pubkey(&secp_ctx,
436                                 msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
437                         NextPacketDetails {
438                                 next_packet_pubkey, outgoing_scid: short_channel_id, outgoing_amt_msat: amt_to_forward,
439                                 outgoing_cltv_value
440                         }
441                 },
442                 onion_utils::Hop::Receive { .. } => return Ok((next_hop, shared_secret, None)),
443                 onion_utils::Hop::Forward { next_hop_data: msgs::InboundOnionPayload::Receive { .. }, .. } |
444                         onion_utils::Hop::Forward { next_hop_data: msgs::InboundOnionPayload::BlindedReceive { .. }, .. } =>
445                 {
446                         return_err!("Final Node OnionHopData provided for us as an intermediary node", 0x4000 | 22, &[0; 0]);
447                 }
448         };
449
450         Ok((next_hop, shared_secret, Some(next_packet_details)))
451 }
452
453 pub(super) fn check_incoming_htlc_cltv(
454         cur_height: u32, outgoing_cltv_value: u32, cltv_expiry: u32
455 ) -> Result<(), (&'static str, u16)> {
456         if (cltv_expiry as u64) < (outgoing_cltv_value) as u64 + MIN_CLTV_EXPIRY_DELTA as u64 {
457                 return Err((
458                         "Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta",
459                         0x1000 | 13, // incorrect_cltv_expiry
460                 ));
461         }
462         // Theoretically, channel counterparty shouldn't send us a HTLC expiring now,
463         // but we want to be robust wrt to counterparty packet sanitization (see
464         // HTLC_FAIL_BACK_BUFFER rationale).
465         if cltv_expiry <= cur_height + HTLC_FAIL_BACK_BUFFER as u32 { // expiry_too_soon
466                 return Err(("CLTV expiry is too close", 0x1000 | 14));
467         }
468         if cltv_expiry > cur_height + CLTV_FAR_FAR_AWAY as u32 { // expiry_too_far
469                 return Err(("CLTV expiry is too far in the future", 21));
470         }
471         // If the HTLC expires ~now, don't bother trying to forward it to our
472         // counterparty. They should fail it anyway, but we don't want to bother with
473         // the round-trips or risk them deciding they definitely want the HTLC and
474         // force-closing to ensure they get it if we're offline.
475         // We previously had a much more aggressive check here which tried to ensure
476         // our counterparty receives an HTLC which has *our* risk threshold met on it,
477         // but there is no need to do that, and since we're a bit conservative with our
478         // risk threshold it just results in failing to forward payments.
479         if (outgoing_cltv_value) as u64 <= (cur_height + LATENCY_GRACE_PERIOD_BLOCKS) as u64 {
480                 return Err(("Outgoing CLTV value is too soon", 0x1000 | 14));
481         }
482
483         Ok(())
484 }
485
486 #[cfg(test)]
487 mod tests {
488         use bitcoin::hashes::Hash;
489         use bitcoin::hashes::sha256::Hash as Sha256;
490         use bitcoin::secp256k1::{PublicKey, SecretKey};
491         use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
492         use crate::ln::ChannelId;
493         use crate::ln::channelmanager::RecipientOnionFields;
494         use crate::ln::features::{ChannelFeatures, NodeFeatures};
495         use crate::ln::msgs;
496         use crate::ln::onion_utils::create_payment_onion;
497         use crate::routing::router::{Path, RouteHop};
498         use crate::util::test_utils;
499
500         #[test]
501         fn test_peel_payment_onion() {
502                 use super::*;
503                 let secp_ctx = Secp256k1::new();
504
505                 let bob = crate::sign::KeysManager::new(&[2; 32], 42, 42);
506                 let bob_pk = PublicKey::from_secret_key(&secp_ctx, &bob.get_node_secret_key());
507                 let charlie = crate::sign::KeysManager::new(&[3; 32], 42, 42);
508                 let charlie_pk = PublicKey::from_secret_key(&secp_ctx, &charlie.get_node_secret_key());
509
510                 let (session_priv, total_amt_msat, cur_height, recipient_onion, preimage, payment_hash,
511                         prng_seed, hops, recipient_amount, pay_secret) = payment_onion_args(bob_pk, charlie_pk);
512
513                 let path = Path {
514                         hops: hops,
515                         blinded_tail: None,
516                 };
517
518                 let (onion, amount_msat, cltv_expiry) = create_payment_onion(
519                         &secp_ctx, &path, &session_priv, total_amt_msat, recipient_onion, cur_height,
520                         &payment_hash, &Some(preimage), prng_seed
521                 ).unwrap();
522
523                 let msg = make_update_add_msg(amount_msat, cltv_expiry, payment_hash, onion);
524                 let logger = test_utils::TestLogger::with_id("bob".to_string());
525
526                 let peeled = peel_payment_onion(&msg, &&bob, &&logger, &secp_ctx, cur_height, true, false)
527                         .map_err(|e| e.msg).unwrap();
528
529                 let next_onion = match peeled.routing {
530                         PendingHTLCRouting::Forward { onion_packet, .. } => {
531                                 onion_packet
532                         },
533                         _ => panic!("expected a forwarded onion"),
534                 };
535
536                 let msg2 = make_update_add_msg(amount_msat, cltv_expiry, payment_hash, next_onion);
537                 let peeled2 = peel_payment_onion(&msg2, &&charlie, &&logger, &secp_ctx, cur_height, true, false)
538                         .map_err(|e| e.msg).unwrap();
539
540                 match peeled2.routing {
541                         PendingHTLCRouting::ReceiveKeysend { payment_preimage, payment_data, incoming_cltv_expiry, .. } => {
542                                 assert_eq!(payment_preimage, preimage);
543                                 assert_eq!(peeled2.outgoing_amt_msat, recipient_amount);
544                                 assert_eq!(incoming_cltv_expiry, peeled2.outgoing_cltv_value);
545                                 let msgs::FinalOnionHopData{total_msat, payment_secret} = payment_data.unwrap();
546                                 assert_eq!(total_msat, total_amt_msat);
547                                 assert_eq!(payment_secret, pay_secret);
548                         },
549                         _ => panic!("expected a received keysend"),
550                 };
551         }
552
553         fn make_update_add_msg(
554                 amount_msat: u64, cltv_expiry: u32, payment_hash: PaymentHash,
555                 onion_routing_packet: msgs::OnionPacket
556         ) -> msgs::UpdateAddHTLC {
557                 msgs::UpdateAddHTLC {
558                         channel_id: ChannelId::from_bytes([0; 32]),
559                         htlc_id: 0,
560                         amount_msat,
561                         cltv_expiry,
562                         payment_hash,
563                         onion_routing_packet,
564                         skimmed_fee_msat: None,
565                         blinding_point: None,
566                 }
567         }
568
569         fn payment_onion_args(hop_pk: PublicKey, recipient_pk: PublicKey) -> (
570                 SecretKey, u64, u32, RecipientOnionFields, PaymentPreimage, PaymentHash, [u8; 32],
571                 Vec<RouteHop>, u64, PaymentSecret,
572         ) {
573                 let session_priv_bytes = [42; 32];
574                 let session_priv = SecretKey::from_slice(&session_priv_bytes).unwrap();
575                 let total_amt_msat = 1000;
576                 let cur_height = 1000;
577                 let pay_secret = PaymentSecret([99; 32]);
578                 let recipient_onion = RecipientOnionFields::secret_only(pay_secret);
579                 let preimage_bytes = [43; 32];
580                 let preimage = PaymentPreimage(preimage_bytes);
581                 let rhash_bytes = Sha256::hash(&preimage_bytes).to_byte_array();
582                 let payment_hash = PaymentHash(rhash_bytes);
583                 let prng_seed = [44; 32];
584
585                 // make a route alice -> bob -> charlie
586                 let hop_fee = 1;
587                 let recipient_amount = total_amt_msat - hop_fee;
588                 let hops = vec![
589                         RouteHop {
590                                 pubkey: hop_pk,
591                                 fee_msat: hop_fee,
592                                 cltv_expiry_delta: 42,
593                                 short_channel_id: 1,
594                                 node_features: NodeFeatures::empty(),
595                                 channel_features: ChannelFeatures::empty(),
596                                 maybe_announced_channel: false,
597                         },
598                         RouteHop {
599                                 pubkey: recipient_pk,
600                                 fee_msat: recipient_amount,
601                                 cltv_expiry_delta: 42,
602                                 short_channel_id: 2,
603                                 node_features: NodeFeatures::empty(),
604                                 channel_features: ChannelFeatures::empty(),
605                                 maybe_announced_channel: false,
606                         }
607                 ];
608
609                 (session_priv, total_amt_msat, cur_height, recipient_onion, preimage, payment_hash,
610                         prng_seed, hops, recipient_amount, pay_secret)
611         }
612
613 }