Skip to content

Commit

Permalink
Update Payment Tlvs to also contain the Option<Padding>
Browse files Browse the repository at this point in the history
Co-authored-by: Jeffrey Czyz <[email protected]>
  • Loading branch information
shaavan and jkczyz committed Sep 27, 2024
1 parent 9015af5 commit 0cb725b
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 23 deletions.
73 changes: 60 additions & 13 deletions lightning/src/blinded_path/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};

use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode, NodeIdLookUp};
use crate::blinded_path::utils;
use crate::blinded_path::utils::{self, Padding};
use crate::crypto::streams::ChaChaPolyReadAdapter;
use crate::io;
use crate::io::Cursor;
Expand Down Expand Up @@ -90,7 +90,7 @@ impl BlindedPaymentPath {
// be in relation to a specific channel.
let htlc_maximum_msat = u64::max_value();
Self::new(
&[], payee_node_id, payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta,
&mut [], payee_node_id, payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta,
entropy_source, secp_ctx
)
}
Expand All @@ -103,7 +103,7 @@ impl BlindedPaymentPath {
/// * any unknown features are required in the provided [`ForwardTlvs`]
// TODO: make all payloads the same size with padding + add dummy hops
pub fn new<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
intermediate_nodes: &[PaymentForwardNode], payee_node_id: PublicKey,
intermediate_nodes: &mut [PaymentForwardNode], payee_node_id: PublicKey,
payee_tlvs: ReceiveTlvs, htlc_maximum_msat: u64, min_final_cltv_expiry_delta: u16,
entropy_source: ES, secp_ctx: &Secp256k1<T>,
) -> Result<Self, ()> where ES::Target: EntropySource {
Expand Down Expand Up @@ -234,6 +234,8 @@ pub struct PaymentForwardNode {
/// Data to construct a [`BlindedHop`] for forwarding a payment.
#[derive(Clone, Debug)]
pub struct ForwardTlvs {
/// The padding data used to make all packets of a blinded path the same size
pub padding: Option<Padding>,
/// The short channel id this payment should be forwarded out over.
pub short_channel_id: u64,
/// Payment parameters for relaying over [`Self::short_channel_id`].
Expand All @@ -254,6 +256,8 @@ pub struct ForwardTlvs {
/// may not be valid if received by another lightning implementation.
#[derive(Clone, Debug)]
pub struct ReceiveTlvs {
/// The padding data used to make all packets of a blinded path the same size
pub padding: Option<Padding>,
/// Used to authenticate the sender of a payment to the receiver and tie MPP HTLCs together.
pub payment_secret: PaymentSecret,
/// Constraints for the receiver of this payment.
Expand All @@ -265,6 +269,7 @@ pub struct ReceiveTlvs {
/// Data to construct a [`BlindedHop`] for sending a payment over.
///
/// [`BlindedHop`]: crate::blinded_path::BlindedHop
#[derive(Clone)]
pub(crate) enum BlindedPaymentTlvs {
/// This blinded payment data is for a forwarding node.
Forward(ForwardTlvs),
Expand All @@ -284,6 +289,28 @@ enum BlindedPaymentTlvsMut<'a> {
Receive(&'a mut ReceiveTlvs),
}

impl<'a> BlindedPaymentTlvsMut<'a> {
pub(crate) fn pad_to_length(mut self, length: usize) -> Self {
let padding = match length.checked_sub(self.serialized_length()) {
Some(length) => Some(Padding::new(length)),
None => {
debug_assert!(
false,
"Size of this packet should not be larger than the size of largest packet."
);
None
}
};

match self {
BlindedPaymentTlvsMut::Forward(ref mut tlvs) => tlvs.padding = padding,
BlindedPaymentTlvsMut::Receive(ref mut tlvs) => tlvs.padding = padding,
}

self
}
}

/// Parameters for relaying over a given [`BlindedHop`].
///
/// [`BlindedHop`]: crate::blinded_path::BlindedHop
Expand Down Expand Up @@ -396,6 +423,7 @@ impl Writeable for ForwardTlvs {
if self.features == BlindedHopFeatures::empty() { None }
else { Some(WithoutLength(&self.features)) };
encode_tlv_stream!(w, {
(1, self.padding, option),
(2, self.short_channel_id, required),
(10, self.payment_relay, required),
(12, self.payment_constraints, required),
Expand All @@ -408,6 +436,7 @@ impl Writeable for ForwardTlvs {
impl Writeable for ReceiveTlvs {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
encode_tlv_stream!(w, {
(1, self.padding, option),
(12, self.payment_constraints, required),
(65536, self.payment_secret, required),
(65537, self.payment_context, required)
Expand All @@ -418,7 +447,6 @@ impl Writeable for ReceiveTlvs {

impl<'a> Writeable for BlindedPaymentTlvsRef<'a> {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
// TODO: write padding
match self {
Self::Forward(tlvs) => tlvs.write(w)?,
Self::Receive(tlvs) => tlvs.write(w)?,
Expand All @@ -429,7 +457,6 @@ impl<'a> Writeable for BlindedPaymentTlvsRef<'a> {

impl<'a> Writeable for BlindedPaymentTlvsMut<'a> {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
// TODO: write padding
match self {
Self::Forward(tlvs) => tlvs.write(w)?,
Self::Receive(tlvs) => tlvs.write(w)?,
Expand Down Expand Up @@ -457,6 +484,7 @@ impl Readable for BlindedPaymentTlvs {
return Err(DecodeError::InvalidValue)
}
Ok(BlindedPaymentTlvs::Forward(ForwardTlvs {
padding: None,
short_channel_id,
payment_relay: payment_relay.ok_or(DecodeError::InvalidValue)?,
payment_constraints: payment_constraints.0.unwrap(),
Expand All @@ -466,6 +494,7 @@ impl Readable for BlindedPaymentTlvs {
} else {
if payment_relay.is_some() || features.is_some() { return Err(DecodeError::InvalidValue) }
Ok(BlindedPaymentTlvs::Receive(ReceiveTlvs {
padding: None,
payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?,
payment_constraints: payment_constraints.0.unwrap(),
payment_context: payment_context.0.unwrap(),
Expand All @@ -476,15 +505,20 @@ impl Readable for BlindedPaymentTlvs {

/// Construct blinded payment hops for the given `intermediate_nodes` and payee info.
pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[PaymentForwardNode],
payee_node_id: PublicKey, payee_tlvs: ReceiveTlvs, session_priv: &SecretKey,
secp_ctx: &Secp256k1<T>, intermediate_nodes: &mut [PaymentForwardNode],
payee_node_id: PublicKey, mut payee_tlvs: ReceiveTlvs, session_priv: &SecretKey,
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
let pks = intermediate_nodes.iter().map(|node| node.node_id)
.chain(core::iter::once(payee_node_id));
let tlvs = intermediate_nodes.iter().map(|node| BlindedPaymentTlvsRef::Forward(&node.tlvs))
.chain(core::iter::once(BlindedPaymentTlvsRef::Receive(&payee_tlvs)));

let path = pks.zip(tlvs);
let max_length = intermediate_nodes.iter().map(|node| BlindedPaymentTlvsRef::Forward(&node.tlvs))
.chain(core::iter::once(BlindedPaymentTlvsRef::Receive(&payee_tlvs)))
.map(|tlv| tlv.serialized_length())
.max()
.unwrap_or(0);

let path = intermediate_nodes
.iter_mut()
.map(|node| (node.node_id, BlindedPaymentTlvsMut::Forward(&mut node.tlvs)))
.chain(core::iter::once((payee_node_id, BlindedPaymentTlvsMut::Receive(&mut payee_tlvs))))
.map(|(pubkey, tlvs)| (pubkey, tlvs.pad_to_length(max_length)));

utils::construct_blinded_hops(secp_ctx, path, session_priv)
}
Expand Down Expand Up @@ -661,6 +695,7 @@ mod tests {
let intermediate_nodes = vec![PaymentForwardNode {
node_id: dummy_pk,
tlvs: ForwardTlvs {
padding: None,
short_channel_id: 0,
payment_relay: PaymentRelay {
cltv_expiry_delta: 144,
Expand All @@ -678,6 +713,7 @@ mod tests {
}, PaymentForwardNode {
node_id: dummy_pk,
tlvs: ForwardTlvs {
padding: None,
short_channel_id: 0,
payment_relay: PaymentRelay {
cltv_expiry_delta: 144,
Expand All @@ -694,6 +730,7 @@ mod tests {
htlc_maximum_msat: u64::max_value(),
}];
let recv_tlvs = ReceiveTlvs {
padding: None,
payment_secret: PaymentSecret([0; 32]),
payment_constraints: PaymentConstraints {
max_cltv_expiry: 0,
Expand All @@ -713,6 +750,7 @@ mod tests {
#[test]
fn compute_payinfo_1_hop() {
let recv_tlvs = ReceiveTlvs {
padding: None,
payment_secret: PaymentSecret([0; 32]),
payment_constraints: PaymentConstraints {
max_cltv_expiry: 0,
Expand All @@ -736,6 +774,7 @@ mod tests {
let intermediate_nodes = vec![PaymentForwardNode {
node_id: dummy_pk,
tlvs: ForwardTlvs {
padding: None,
short_channel_id: 0,
payment_relay: PaymentRelay {
cltv_expiry_delta: 0,
Expand All @@ -753,6 +792,7 @@ mod tests {
}, PaymentForwardNode {
node_id: dummy_pk,
tlvs: ForwardTlvs {
padding: None,
short_channel_id: 0,
payment_relay: PaymentRelay {
cltv_expiry_delta: 0,
Expand All @@ -769,6 +809,7 @@ mod tests {
htlc_maximum_msat: u64::max_value()
}];
let recv_tlvs = ReceiveTlvs {
padding: None,
payment_secret: PaymentSecret([0; 32]),
payment_constraints: PaymentConstraints {
max_cltv_expiry: 0,
Expand All @@ -789,6 +830,7 @@ mod tests {
let intermediate_nodes = vec![PaymentForwardNode {
node_id: dummy_pk,
tlvs: ForwardTlvs {
padding: None,
short_channel_id: 0,
payment_relay: PaymentRelay {
cltv_expiry_delta: 0,
Expand All @@ -806,6 +848,7 @@ mod tests {
}, PaymentForwardNode {
node_id: dummy_pk,
tlvs: ForwardTlvs {
padding: None,
short_channel_id: 0,
payment_relay: PaymentRelay {
cltv_expiry_delta: 0,
Expand All @@ -822,6 +865,7 @@ mod tests {
htlc_maximum_msat: u64::max_value()
}];
let recv_tlvs = ReceiveTlvs {
padding: None,
payment_secret: PaymentSecret([0; 32]),
payment_constraints: PaymentConstraints {
max_cltv_expiry: 0,
Expand All @@ -846,6 +890,7 @@ mod tests {
let intermediate_nodes = vec![PaymentForwardNode {
node_id: dummy_pk,
tlvs: ForwardTlvs {
padding: None,
short_channel_id: 0,
payment_relay: PaymentRelay {
cltv_expiry_delta: 0,
Expand All @@ -863,6 +908,7 @@ mod tests {
}, PaymentForwardNode {
node_id: dummy_pk,
tlvs: ForwardTlvs {
padding: None,
short_channel_id: 0,
payment_relay: PaymentRelay {
cltv_expiry_delta: 0,
Expand All @@ -879,6 +925,7 @@ mod tests {
htlc_maximum_msat: 10_000
}];
let recv_tlvs = ReceiveTlvs {
padding: None,
payment_secret: PaymentSecret([0; 32]),
payment_constraints: PaymentConstraints {
max_cltv_expiry: 0,
Expand Down
15 changes: 10 additions & 5 deletions lightning/src/ln/blinded_payment_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ fn blinded_payment_path(
intermediate_nodes.push(PaymentForwardNode {
node_id: *node_id,
tlvs: ForwardTlvs {
padding: None,
short_channel_id: chan_upd.short_channel_id,
payment_relay: PaymentRelay {
cltv_expiry_delta: chan_upd.cltv_expiry_delta,
Expand All @@ -66,6 +67,7 @@ fn blinded_payment_path(
});
}
let payee_tlvs = ReceiveTlvs {
padding: None,
payment_secret,
payment_constraints: PaymentConstraints {
max_cltv_expiry: u32::max_value(),
Expand All @@ -76,7 +78,7 @@ fn blinded_payment_path(
};
let mut secp_ctx = Secp256k1::new();
BlindedPaymentPath::new(
&intermediate_nodes[..], *node_ids.last().unwrap(), payee_tlvs,
&mut intermediate_nodes[..], *node_ids.last().unwrap(), payee_tlvs,
intro_node_max_htlc_opt.unwrap_or_else(|| channel_upds.last().unwrap().htlc_maximum_msat),
TEST_FINAL_CLTV as u16, keys_manager, &secp_ctx
).unwrap()
Expand Down Expand Up @@ -113,6 +115,7 @@ fn do_one_hop_blinded_path(success: bool) {
let amt_msat = 5000;
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[1], Some(amt_msat), None);
let payee_tlvs = ReceiveTlvs {
padding: None,
payment_secret,
payment_constraints: PaymentConstraints {
max_cltv_expiry: u32::max_value(),
Expand All @@ -122,7 +125,7 @@ fn do_one_hop_blinded_path(success: bool) {
};
let mut secp_ctx = Secp256k1::new();
let blinded_path = BlindedPaymentPath::new(
&[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
&mut [], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
&chanmon_cfgs[1].keys_manager, &secp_ctx
).unwrap();

Expand Down Expand Up @@ -157,6 +160,7 @@ fn mpp_to_one_hop_blinded_path() {
let amt_msat = 15_000_000;
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[3], Some(amt_msat), None);
let payee_tlvs = ReceiveTlvs {
padding: None,
payment_secret,
payment_constraints: PaymentConstraints {
max_cltv_expiry: u32::max_value(),
Expand All @@ -165,7 +169,7 @@ fn mpp_to_one_hop_blinded_path() {
payment_context: PaymentContext::unknown(),
};
let blinded_path = BlindedPaymentPath::new(
&[], nodes[3].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
&mut [], nodes[3].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
&chanmon_cfgs[3].keys_manager, &secp_ctx
).unwrap();

Expand Down Expand Up @@ -298,7 +302,7 @@ fn do_forward_checks_failure(check: ForwardCheckFail, intro_fails: bool) {
let mut route_params = get_blinded_route_parameters(amt_msat, payment_secret, 1, 1_0000_0000,
nodes.iter().skip(1).map(|n| n.node.get_our_node_id()).collect(),
&[&chan_upd_1_2, &chan_upd_2_3], &chanmon_cfgs[3].keys_manager);
route_params.payment_params.max_path_length = 18;
route_params.payment_params.max_path_length = 17;

let route = get_route(&nodes[0], &route_params).unwrap();
node_cfgs[0].router.expect_find_route(route_params.clone(), Ok(route.clone()));
Expand Down Expand Up @@ -1303,6 +1307,7 @@ fn custom_tlvs_to_blinded_path() {
let amt_msat = 5000;
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[1], Some(amt_msat), None);
let payee_tlvs = ReceiveTlvs {
padding: None,
payment_secret,
payment_constraints: PaymentConstraints {
max_cltv_expiry: u32::max_value(),
Expand All @@ -1312,7 +1317,7 @@ fn custom_tlvs_to_blinded_path() {
};
let mut secp_ctx = Secp256k1::new();
let blinded_path = BlindedPaymentPath::new(
&[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
&mut [], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
&chanmon_cfgs[1].keys_manager, &secp_ctx
).unwrap();

Expand Down
1 change: 1 addition & 0 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9680,6 +9680,7 @@ where
let max_cltv_expiry = self.best_block.read().unwrap().height + CLTV_FAR_FAR_AWAY
+ LATENCY_GRACE_PERIOD_BLOCKS;
let payee_tlvs = ReceiveTlvs {
padding: None,
payment_secret,
payment_constraints: PaymentConstraints {
max_cltv_expiry,
Expand Down
3 changes: 2 additions & 1 deletion lightning/src/ln/max_payment_path_len_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ fn one_hop_blinded_path_with_custom_tlv() {
let amt_msat = 100_000;
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), None);
let payee_tlvs = ReceiveTlvs {
padding: None,
payment_secret,
payment_constraints: PaymentConstraints {
max_cltv_expiry: u32::max_value(),
Expand All @@ -167,7 +168,7 @@ fn one_hop_blinded_path_with_custom_tlv() {
};
let mut secp_ctx = Secp256k1::new();
let blinded_path = BlindedPaymentPath::new(
&[], nodes[2].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
&mut [], nodes[2].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
&chanmon_cfgs[2].keys_manager, &secp_ctx
).unwrap();
let route_params = RouteParameters::from_payment_params_and_value(
Expand Down
6 changes: 4 additions & 2 deletions lightning/src/ln/msgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2822,7 +2822,8 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, NS)> for InboundOnionPayload wh
let mut reader = FixedLengthReader::new(&mut s, enc_tlvs.len() as u64);
match ChaChaPolyReadAdapter::read(&mut reader, rho)? {
ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Forward(ForwardTlvs {
short_channel_id, payment_relay, payment_constraints, features, next_blinding_override
padding: _, short_channel_id, payment_relay,
payment_constraints, features, next_blinding_override
})} => {
if amt.is_some() || cltv_value.is_some() || total_msat.is_some() ||
keysend_preimage.is_some()
Expand All @@ -2839,7 +2840,8 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, NS)> for InboundOnionPayload wh
})
},
ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(ReceiveTlvs {
payment_secret, payment_constraints, payment_context
padding: _, payment_secret, payment_constraints,
payment_context
})} => {
if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) }
Ok(Self::BlindedReceive {
Expand Down
Loading

0 comments on commit 0cb725b

Please sign in to comment.