Skip to content

Commit 47d34c3

Browse files
Support forwarding blinded HTLCs as intro node.
Error handling will be completed in upcoming commits.
1 parent 1a7254c commit 47d34c3

File tree

2 files changed

+61
-8
lines changed

2 files changed

+61
-8
lines changed

lightning/src/blinded_path/payment.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
187187
}
188188

189189
/// `None` if underflow occurs.
190-
fn amt_to_forward_msat(inbound_amt_msat: u64, payment_relay: &PaymentRelay) -> Option<u64> {
190+
pub(crate) fn amt_to_forward_msat(inbound_amt_msat: u64, payment_relay: &PaymentRelay) -> Option<u64> {
191191
let inbound_amt = inbound_amt_msat as u128;
192192
let base = payment_relay.fee_base_msat as u128;
193193
let prop = payment_relay.fee_proportional_millionths as u128;

lightning/src/ln/onion_payment.rs

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ use bitcoin::hashes::Hash;
66
use bitcoin::hashes::sha256::Hash as Sha256;
77
use bitcoin::secp256k1::{self, Secp256k1, PublicKey};
88

9+
use crate::blinded_path;
10+
use crate::blinded_path::payment::{PaymentConstraints, PaymentRelay};
911
use crate::chain::channelmonitor::{HTLC_FAIL_BACK_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS};
1012
use crate::ln::PaymentHash;
11-
use crate::ln::channelmanager::{CLTV_FAR_FAR_AWAY, HTLCFailureMsg, MIN_CLTV_EXPIRY_DELTA, PendingHTLCInfo, PendingHTLCRouting};
13+
use crate::ln::channelmanager::{BlindedForward, CLTV_FAR_FAR_AWAY, HTLCFailureMsg, MIN_CLTV_EXPIRY_DELTA, PendingHTLCInfo, PendingHTLCRouting};
14+
use crate::ln::features::BlindedHopFeatures;
1215
use crate::ln::msgs;
1316
use crate::ln::onion_utils;
1417
use crate::ln::onion_utils::{HTLCFailReason, INVALID_ONION_BLINDING};
@@ -28,6 +31,23 @@ pub struct InboundOnionErr {
2831
pub msg: &'static str,
2932
}
3033

34+
fn check_blinded_forward(
35+
inbound_amt_msat: u64, inbound_cltv_expiry: u32, payment_relay: &PaymentRelay,
36+
payment_constraints: &PaymentConstraints, features: &BlindedHopFeatures
37+
) -> Result<(u64, u32), ()> {
38+
let amt_to_forward = blinded_path::payment::amt_to_forward_msat(
39+
inbound_amt_msat, payment_relay
40+
).ok_or(())?;
41+
let outgoing_cltv_value = inbound_cltv_expiry.checked_sub(
42+
payment_relay.cltv_expiry_delta as u32
43+
).ok_or(())?;
44+
if inbound_amt_msat < payment_constraints.htlc_minimum_msat ||
45+
outgoing_cltv_value > payment_constraints.max_cltv_expiry
46+
{ return Err(()) }
47+
if features.requires_unknown_bits_from(&BlindedHopFeatures::empty()) { return Err(()) }
48+
Ok((amt_to_forward, outgoing_cltv_value))
49+
}
50+
3151
pub(super) fn create_fwd_pending_htlc_info(
3252
msg: &msgs::UpdateAddHTLC, hop_data: msgs::InboundOnionPayload, hop_hmac: [u8; 32],
3353
new_packet_bytes: [u8; onion_utils::ONION_DATA_LEN], shared_secret: [u8; 32],
@@ -41,10 +61,27 @@ pub(super) fn create_fwd_pending_htlc_info(
4161
hmac: hop_hmac,
4262
};
4363

44-
let (short_channel_id, amt_to_forward, outgoing_cltv_value) = match hop_data {
64+
let (
65+
short_channel_id, amt_to_forward, outgoing_cltv_value, inbound_blinding_point
66+
) = match hop_data {
4567
msgs::InboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } =>
46-
(short_channel_id, amt_to_forward, outgoing_cltv_value),
47-
msgs::InboundOnionPayload::BlindedForward { .. } => todo!(),
68+
(short_channel_id, amt_to_forward, outgoing_cltv_value, None),
69+
msgs::InboundOnionPayload::BlindedForward {
70+
short_channel_id, payment_relay, payment_constraints, intro_node_blinding_point, features,
71+
} => {
72+
let (amt_to_forward, outgoing_cltv_value) = check_blinded_forward(
73+
msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features
74+
).map_err(|()| {
75+
// We should be returning malformed here if `msg.blinding_point` is set, but this is
76+
// unreachable right now since we checked it in `decode_update_add_htlc_onion`.
77+
InboundOnionErr {
78+
msg: "Underflow calculating outbound amount or cltv value for blinded forward",
79+
err_code: INVALID_ONION_BLINDING,
80+
err_data: vec![0; 32],
81+
}
82+
})?;
83+
(short_channel_id, amt_to_forward, outgoing_cltv_value, Some(intro_node_blinding_point))
84+
},
4885
msgs::InboundOnionPayload::Receive { .. } | msgs::InboundOnionPayload::BlindedReceive { .. } =>
4986
return Err(InboundOnionErr {
5087
msg: "Final Node OnionHopData provided for us as an intermediary node",
@@ -57,7 +94,7 @@ pub(super) fn create_fwd_pending_htlc_info(
5794
routing: PendingHTLCRouting::Forward {
5895
onion_packet: outgoing_packet,
5996
short_channel_id,
60-
blinded: None,
97+
blinded: inbound_blinding_point.map(|bp| BlindedForward { inbound_blinding_point: bp }),
6198
},
6299
payment_hash: msg.payment_hash,
63100
incoming_shared_secret: shared_secret,
@@ -336,9 +373,25 @@ where
336373
}
337374
},
338375
onion_utils::Hop::Forward {
339-
next_hop_data: msgs::InboundOnionPayload::BlindedForward { .. }, ..
376+
next_hop_data: msgs::InboundOnionPayload::BlindedForward {
377+
short_channel_id, ref payment_relay, ref payment_constraints, ref features, ..
378+
}, ..
340379
} => {
341-
todo!()
380+
let (amt_to_forward, outgoing_cltv_value) = match check_blinded_forward(
381+
msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features
382+
) {
383+
Ok((amt, cltv)) => (amt, cltv),
384+
Err(()) => {
385+
return_err!("Underflow calculating outbound amount or cltv value for blinded forward",
386+
INVALID_ONION_BLINDING, &[0; 32]);
387+
}
388+
};
389+
let next_packet_pubkey = onion_utils::next_hop_pubkey(&secp_ctx,
390+
msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
391+
NextPacketDetails {
392+
next_packet_pubkey, outgoing_scid: short_channel_id, outgoing_amt_msat: amt_to_forward,
393+
outgoing_cltv_value
394+
}
342395
},
343396
onion_utils::Hop::Receive { .. } => return Ok((next_hop, shared_secret, None)),
344397
onion_utils::Hop::Forward { next_hop_data: msgs::InboundOnionPayload::Receive { .. }, .. } |

0 commit comments

Comments
 (0)