Skip to content

Commit 56e83b8

Browse files
Extract onion_utils::build_onion_payloads_callback helper.
Will be useful when we want to calculate the total size of the payloads without actually allocating for them.
1 parent 2de600b commit 56e83b8

File tree

1 file changed

+93
-40
lines changed

1 file changed

+93
-40
lines changed

lightning/src/ln/onion_utils.rs

Lines changed: 93 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77
// You may not use this file except in accordance with one or both of these
88
// licenses.
99

10+
use crate::blinded_path::BlindedHop;
1011
use crate::crypto::chacha20::ChaCha20;
1112
use crate::crypto::streams::ChaChaReader;
1213
use crate::ln::channelmanager::{HTLCSource, RecipientOnionFields};
1314
use crate::ln::msgs;
1415
use crate::ln::types::{PaymentHash, PaymentPreimage};
1516
use crate::ln::wire::Encode;
1617
use crate::routing::gossip::NetworkUpdate;
17-
use crate::routing::router::{BlindedTail, Path, RouteHop};
18+
use crate::routing::router::{Path, RouteHop};
1819
use crate::sign::NodeSigner;
1920
use crate::util::errors::{self, APIError};
2021
use crate::util::logger::Logger;
@@ -173,19 +174,31 @@ pub(super) fn construct_onion_keys<T: secp256k1::Signing>(
173174
Ok(res)
174175
}
175176

176-
/// returns the hop data, as well as the first-hop value_msat and CLTV value we should send.
177-
pub(super) fn build_onion_payloads<'a>(
178-
path: &'a Path, total_msat: u64, recipient_onion: &'a RecipientOnionFields,
179-
starting_htlc_offset: u32, keysend_preimage: &Option<PaymentPreimage>,
180-
) -> Result<(Vec<msgs::OutboundOnionPayload<'a>>, u64, u32), APIError> {
177+
struct BlindedTailHopIter<'a, I: Iterator<Item = &'a BlindedHop>> {
178+
hops: I,
179+
blinding_point: PublicKey,
180+
final_value_msat: u64,
181+
excess_final_cltv_expiry_delta: u32,
182+
}
183+
enum PayloadCallbackAction {
184+
PushBack,
185+
Insert { idx: usize },
186+
}
187+
fn build_onion_payloads_callback<'a, H, B, F>(
188+
hops: H, mut blinded_tail: Option<BlindedTailHopIter<'a, B>>, total_msat: u64,
189+
recipient_onion: &'a RecipientOnionFields, starting_htlc_offset: u32,
190+
keysend_preimage: &Option<PaymentPreimage>, mut callback: F,
191+
) -> Result<(u64, u32), APIError>
192+
where
193+
H: DoubleEndedIterator<Item = &'a RouteHop>,
194+
B: ExactSizeIterator<Item = &'a BlindedHop>,
195+
F: FnMut(PayloadCallbackAction, msgs::OutboundOnionPayload<'a>),
196+
{
181197
let mut cur_value_msat = 0u64;
182198
let mut cur_cltv = starting_htlc_offset;
183199
let mut last_short_channel_id = 0;
184-
let mut res: Vec<msgs::OutboundOnionPayload> = Vec::with_capacity(
185-
path.hops.len() + path.blinded_tail.as_ref().map_or(0, |t| t.hops.len()),
186-
);
187200

188-
for (idx, hop) in path.hops.iter().rev().enumerate() {
201+
for (idx, hop) in hops.rev().enumerate() {
189202
// First hop gets special values so that it can check, on receipt, that everything is
190203
// exactly as it should be (and the next hop isn't trying to probe to find out if we're
191204
// the intended recipient).
@@ -196,53 +209,63 @@ pub(super) fn build_onion_payloads<'a>(
196209
cur_cltv
197210
};
198211
if idx == 0 {
199-
if let Some(BlindedTail {
212+
if let Some(BlindedTailHopIter {
200213
blinding_point,
201214
hops,
202215
final_value_msat,
203216
excess_final_cltv_expiry_delta,
204217
..
205-
}) = &path.blinded_tail
218+
}) = blinded_tail.take()
206219
{
207-
let mut blinding_point = Some(*blinding_point);
208-
for (i, blinded_hop) in hops.iter().enumerate() {
209-
if i == hops.len() - 1 {
220+
let mut blinding_point = Some(blinding_point);
221+
let hops_len = hops.len();
222+
for (i, blinded_hop) in hops.enumerate() {
223+
if i == hops_len - 1 {
210224
cur_value_msat += final_value_msat;
211-
res.push(msgs::OutboundOnionPayload::BlindedReceive {
212-
sender_intended_htlc_amt_msat: *final_value_msat,
213-
total_msat,
214-
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,
215-
encrypted_tlvs: &blinded_hop.encrypted_payload,
216-
intro_node_blinding_point: blinding_point.take(),
217-
keysend_preimage: *keysend_preimage,
218-
custom_tlvs: &recipient_onion.custom_tlvs,
219-
});
225+
callback(
226+
PayloadCallbackAction::PushBack,
227+
msgs::OutboundOnionPayload::BlindedReceive {
228+
sender_intended_htlc_amt_msat: final_value_msat,
229+
total_msat,
230+
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,
231+
encrypted_tlvs: &blinded_hop.encrypted_payload,
232+
intro_node_blinding_point: blinding_point.take(),
233+
keysend_preimage: *keysend_preimage,
234+
custom_tlvs: &recipient_onion.custom_tlvs,
235+
},
236+
);
220237
} else {
221-
res.push(msgs::OutboundOnionPayload::BlindedForward {
222-
encrypted_tlvs: &blinded_hop.encrypted_payload,
223-
intro_node_blinding_point: blinding_point.take(),
224-
});
238+
callback(
239+
PayloadCallbackAction::PushBack,
240+
msgs::OutboundOnionPayload::BlindedForward {
241+
encrypted_tlvs: &blinded_hop.encrypted_payload,
242+
intro_node_blinding_point: blinding_point.take(),
243+
},
244+
);
225245
}
226246
}
227247
} else {
228-
res.push(msgs::OutboundOnionPayload::Receive {
229-
payment_data: recipient_onion.payment_secret.map(|payment_secret| {
230-
msgs::FinalOnionHopData { payment_secret, total_msat }
231-
}),
232-
payment_metadata: recipient_onion.payment_metadata.as_ref(),
233-
keysend_preimage: *keysend_preimage,
234-
custom_tlvs: &recipient_onion.custom_tlvs,
235-
sender_intended_htlc_amt_msat: value_msat,
236-
cltv_expiry_height: cltv,
237-
});
248+
callback(
249+
PayloadCallbackAction::PushBack,
250+
msgs::OutboundOnionPayload::Receive {
251+
payment_data: recipient_onion.payment_secret.map(|payment_secret| {
252+
msgs::FinalOnionHopData { payment_secret, total_msat }
253+
}),
254+
payment_metadata: recipient_onion.payment_metadata.as_ref(),
255+
keysend_preimage: *keysend_preimage,
256+
custom_tlvs: &recipient_onion.custom_tlvs,
257+
sender_intended_htlc_amt_msat: value_msat,
258+
cltv_expiry_height: cltv,
259+
},
260+
);
238261
}
239262
} else {
240263
let payload = msgs::OutboundOnionPayload::Forward {
241264
short_channel_id: last_short_channel_id,
242265
amt_to_forward: value_msat,
243266
outgoing_cltv_value: cltv,
244267
};
245-
res.insert(0, payload);
268+
callback(PayloadCallbackAction::Insert { idx: 0 }, payload);
246269
}
247270
cur_value_msat += hop.fee_msat;
248271
if cur_value_msat >= 21000000 * 100000000 * 1000 {
@@ -254,7 +277,37 @@ pub(super) fn build_onion_payloads<'a>(
254277
}
255278
last_short_channel_id = hop.short_channel_id;
256279
}
257-
Ok((res, cur_value_msat, cur_cltv))
280+
Ok((cur_value_msat, cur_cltv))
281+
}
282+
283+
/// returns the hop data, as well as the first-hop value_msat and CLTV value we should send.
284+
pub(super) fn build_onion_payloads<'a>(
285+
path: &'a Path, total_msat: u64, recipient_onion: &'a RecipientOnionFields,
286+
starting_htlc_offset: u32, keysend_preimage: &Option<PaymentPreimage>,
287+
) -> Result<(Vec<msgs::OutboundOnionPayload<'a>>, u64, u32), APIError> {
288+
let mut res: Vec<msgs::OutboundOnionPayload> = Vec::with_capacity(
289+
path.hops.len() + path.blinded_tail.as_ref().map_or(0, |t| t.hops.len()),
290+
);
291+
let blinded_tail_with_hop_iter = path.blinded_tail.as_ref().map(|bt| BlindedTailHopIter {
292+
hops: bt.hops.iter(),
293+
blinding_point: bt.blinding_point,
294+
final_value_msat: bt.final_value_msat,
295+
excess_final_cltv_expiry_delta: bt.excess_final_cltv_expiry_delta,
296+
});
297+
298+
let (value_msat, cltv) = build_onion_payloads_callback(
299+
path.hops.iter(),
300+
blinded_tail_with_hop_iter,
301+
total_msat,
302+
recipient_onion,
303+
starting_htlc_offset,
304+
keysend_preimage,
305+
|action, payload| match action {
306+
PayloadCallbackAction::PushBack => res.push(payload),
307+
PayloadCallbackAction::Insert { idx } => res.insert(idx, payload),
308+
},
309+
)?;
310+
Ok((res, value_msat, cltv))
258311
}
259312

260313
/// Length of the onion data packet. Before TLV-based onions this was 20 65-byte hops, though now

0 commit comments

Comments
 (0)