Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serialize blinded Trampoline hops #3007

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 117 additions & 6 deletions lightning/src/ln/msgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1746,9 +1746,9 @@ pub struct FinalOnionHopData {

mod fuzzy_internal_msgs {
use bitcoin::secp256k1::PublicKey;
use crate::blinded_path::payment::{PaymentConstraints, PaymentContext, PaymentRelay};
use crate::blinded_path::payment::{BlindedPaymentPath, PaymentConstraints, PaymentContext, PaymentRelay};
use crate::ln::types::{PaymentPreimage, PaymentSecret};
use crate::ln::features::BlindedHopFeatures;
use crate::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures};
use super::{FinalOnionHopData, TrampolineOnionPacket};

#[allow(unused_imports)]
Expand Down Expand Up @@ -1830,14 +1830,41 @@ mod fuzzy_internal_msgs {
}
}

pub(crate) enum OutboundTrampolinePayload {
pub(crate) enum OutboundTrampolinePayload<'a> {
#[allow(unused)]
Forward {
/// The value, in msat, of the payment after this hop's fee is deducted.
amt_to_forward: u64,
outgoing_cltv_value: u32,
/// The node id to which the trampoline node must find a route
/// The node id to which the trampoline node must find a route.
outgoing_node_id: PublicKey,
},
#[allow(unused)]
/// This is the last Trampoline hop, whereupon the Trampoline forward mechanism is exited,
/// and payment data is relayed using non-Trampoline blinded hops
LegacyBlindedPathEntry {
/// The value, in msat, of the payment after this hop's fee is deducted.
amt_to_forward: u64,
outgoing_cltv_value: u32,
/// List of blinded path options the last trampoline hop may choose to route through.
payment_paths: Vec<BlindedPaymentPath>,
/// If applicable, features of the BOLT12 invoice being paid.
invoice_features: Option<Bolt12InvoiceFeatures>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this is supposed to be a Bolt12InvoiceFeatures and not a BlindedPathFeatures? I mean it makes sense just want to double-check.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

by BlindedPathFeatures do you mean BlindedHopFeatures?

},
#[allow(unused)]
BlindedForward {
encrypted_tlvs: &'a Vec<u8>,
intro_node_blinding_point: Option<PublicKey>,
},
#[allow(unused)]
BlindedReceive {
sender_intended_htlc_amt_msat: u64,
total_msat: u64,
cltv_expiry_height: u32,
encrypted_tlvs: &'a Vec<u8>,
intro_node_blinding_point: Option<PublicKey>, // Set if the introduction node of the blinded path is the final node
keysend_preimage: Option<PaymentPreimage>,
custom_tlvs: &'a Vec<(u64, Vec<u8>)>,
}
}

Expand Down Expand Up @@ -2754,7 +2781,7 @@ impl<'a> Writeable for OutboundOnionPayload<'a> {
}
}

impl Writeable for OutboundTrampolinePayload {
impl<'a> Writeable for OutboundTrampolinePayload<'a> {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
match self {
Self::Forward { amt_to_forward, outgoing_cltv_value, outgoing_node_id } => {
Expand All @@ -2763,6 +2790,36 @@ impl Writeable for OutboundTrampolinePayload {
(4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
(14, outgoing_node_id, required)
});
},
Self::LegacyBlindedPathEntry { amt_to_forward, outgoing_cltv_value, payment_paths, invoice_features } => {
let blinded_path_value: Vec<u8> = payment_paths.iter().flat_map(|p| {
p.inner_blinded_path().encode().into_iter().chain(p.payinfo.encode()).collect::<Vec<u8>>()
}).collect();
let blinded_path_tlv = (22, blinded_path_value);

_encode_varint_length_prefixed_tlv!(w, {
(2, HighZeroBytesDroppedBigSize(*amt_to_forward), required),
(4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
(21, invoice_features.as_ref().map(|m| WithoutLength(m)), option)
}, [&blinded_path_tlv]);
},
Self::BlindedForward { encrypted_tlvs, intro_node_blinding_point} => {
_encode_varint_length_prefixed_tlv!(w, {
(10, **encrypted_tlvs, required_vec),
(12, intro_node_blinding_point, option)
});
},
Self::BlindedReceive { sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, encrypted_tlvs, intro_node_blinding_point, keysend_preimage, custom_tlvs } => {
let keysend_tlv = keysend_preimage.map(|preimage| (5482373484, preimage.encode()));
let mut custom_tlvs: Vec<&(u64, Vec<u8>)> = custom_tlvs.iter().chain(keysend_tlv.iter()).collect();
custom_tlvs.sort_unstable_by_key(|(typ, _)| *typ);
_encode_varint_length_prefixed_tlv!(w, {
(2, HighZeroBytesDroppedBigSize(*sender_intended_htlc_amt_msat), required),
(4, HighZeroBytesDroppedBigSize(*cltv_expiry_height), required),
(10, **encrypted_tlvs, required_vec),
(12, intro_node_blinding_point, option),
(18, HighZeroBytesDroppedBigSize(*total_msat), required)
}, custom_tlvs.iter());
}
}
Ok(())
Expand Down Expand Up @@ -3301,7 +3358,7 @@ mod tests {
use bitcoin::hex::DisplayHex;
use crate::ln::types::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret};
use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket, CommonOpenChannelFields, CommonAcceptChannelFields, TrampolineOnionPacket};
use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket, CommonOpenChannelFields, CommonAcceptChannelFields, TrampolineOnionPacket, OutboundTrampolinePayload};
use crate::ln::msgs::SocketAddress;
use crate::routing::gossip::{NodeAlias, NodeId};
use crate::util::ser::{BigSize, FixedLengthReader, Hostname, LengthReadable, Readable, ReadableArgs, TransactionU16LenLimited, Writeable};
Expand All @@ -3327,6 +3384,8 @@ mod tests {

#[cfg(feature = "std")]
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
use types::features::{BlindedHopFeatures, Bolt12InvoiceFeatures};
use crate::blinded_path::payment::{BlindedPayInfo, BlindedPaymentPath};
#[cfg(feature = "std")]
use crate::ln::msgs::SocketAddressParseError;

Expand Down Expand Up @@ -4674,6 +4733,58 @@ mod tests {
assert_eq!(encoded_trampoline_packet, expected_eclair_trampoline_packet);
}

#[test]
fn encoding_outbound_trampoline_payload() {
let mut trampoline_features = Bolt12InvoiceFeatures::empty();
trampoline_features.set_basic_mpp_optional();
let introduction_node = PublicKey::from_slice(&<Vec<u8>>::from_hex("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()).unwrap();
let blinding_point = PublicKey::from_slice(&<Vec<u8>>::from_hex("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619").unwrap()).unwrap();
let trampoline_payload = OutboundTrampolinePayload::LegacyBlindedPathEntry {
amt_to_forward: 150_000_000,
outgoing_cltv_value: 800_000,
payment_paths: vec![
BlindedPaymentPath::from_raw(
introduction_node,
blinding_point,
vec![],
BlindedPayInfo{
fee_base_msat: 500,
fee_proportional_millionths: 1_000,
cltv_expiry_delta: 36,
htlc_minimum_msat: 1,
htlc_maximum_msat: 500_000_000,
features: BlindedHopFeatures::empty(),
}
)
],
invoice_features: Some(trampoline_features),
};
let serialized_payload = trampoline_payload.encode().to_lower_hex_string();
assert_eq!(serialized_payload, "71020408f0d18004030c35001503020000165f032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e66868099102eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f28368661900000001f4000003e800240000000000000001000000001dcd65000000");
}

#[test]
fn encode_trampoline_blinded_path_payload() {
let trampoline_payload_eve = OutboundTrampolinePayload::BlindedReceive {
sender_intended_htlc_amt_msat: 150_000_000,
total_msat: 150_000_000,
cltv_expiry_height: 800_000,
encrypted_tlvs: &<Vec<u8>>::from_hex("bcd747394fbd4d99588da075a623316e15a576df5bc785cccc7cd6ec7b398acce6faf520175f9ec920f2ef261cdb83dc28cc3a0eeb970107b3306489bf771ef5b1213bca811d345285405861d08a655b6c237fa247a8b4491beee20c878a60e9816492026d8feb9dafa84585b253978db6a0aa2945df5ef445c61e801fb82f43d5f00716baf9fc9b3de50bc22950a36bda8fc27bfb1242e5860c7e687438d4133e058770361a19b6c271a2a07788d34dccc27e39b9829b061a4d960eac4a2c2b0f4de506c24f9af3868c0aff6dda27281c").unwrap(),
intro_node_blinding_point: None,
keysend_preimage: None,
custom_tlvs: &vec![],
};
let eve_payload = trampoline_payload_eve.encode().to_lower_hex_string();
assert_eq!(eve_payload, "e4020408f0d18004030c35000ad1bcd747394fbd4d99588da075a623316e15a576df5bc785cccc7cd6ec7b398acce6faf520175f9ec920f2ef261cdb83dc28cc3a0eeb970107b3306489bf771ef5b1213bca811d345285405861d08a655b6c237fa247a8b4491beee20c878a60e9816492026d8feb9dafa84585b253978db6a0aa2945df5ef445c61e801fb82f43d5f00716baf9fc9b3de50bc22950a36bda8fc27bfb1242e5860c7e687438d4133e058770361a19b6c271a2a07788d34dccc27e39b9829b061a4d960eac4a2c2b0f4de506c24f9af3868c0aff6dda27281c120408f0d180");

let trampoline_payload_dave = OutboundTrampolinePayload::BlindedForward {
encrypted_tlvs: &<Vec<u8>>::from_hex("0ccf3c8a58deaa603f657ee2a5ed9d604eb5c8ca1e5f801989afa8f3ea6d789bbdde2c7e7a1ef9ca8c38d2c54760febad8446d3f273ddb537569ef56613846ccd3aba78a").unwrap(),
intro_node_blinding_point: Some(PublicKey::from_slice(&<Vec<u8>>::from_hex("02988face71e92c345a068f740191fd8e53be14f0bb957ef730d3c5f76087b960e").unwrap()).unwrap()),
};
let dave_payload = trampoline_payload_dave.encode().to_lower_hex_string();
assert_eq!(dave_payload, "690a440ccf3c8a58deaa603f657ee2a5ed9d604eb5c8ca1e5f801989afa8f3ea6d789bbdde2c7e7a1ef9ca8c38d2c54760febad8446d3f273ddb537569ef56613846ccd3aba78a0c2102988face71e92c345a068f740191fd8e53be14f0bb957ef730d3c5f76087b960e")
}

#[test]
fn query_channel_range_end_blocknum() {
let tests: Vec<(u32, u32, u32)> = vec![
Expand Down
Loading