Skip to content

Trampoline onion construction vectors #2899

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

Closed
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions lightning/src/ln/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ mod sealed {
ChannelType | SCIDPrivacy,
// Byte 6
ZeroConf | Keysend,
// Byte 7
Trampoline,
]);
define_context!(ChannelContext, []);
define_context!(Bolt11InvoiceContext, [
Expand Down Expand Up @@ -420,6 +422,9 @@ mod sealed {
define_feature!(55, Keysend, [NodeContext],
"Feature flags for keysend payments.", set_keysend_optional, set_keysend_required,
supports_keysend, requires_keysend);
define_feature!(57, Trampoline, [NodeContext],
"Feature flags for Trampoline routing.", set_trampoline_routing_optional, set_trampoline_routing_required,
supports_trampoline_routing, requires_trampoline_routing);
// Note: update the module-level docs when a new feature bit is added!

#[cfg(test)]
Expand Down
93 changes: 89 additions & 4 deletions lightning/src/ln/msgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1688,13 +1688,22 @@ mod fuzzy_internal_msgs {
amt_to_forward: u64,
outgoing_cltv_value: u32,
},
// This should only be used for nested Trampoline onions
TrampolineForward {
Copy link
Contributor Author

@arik-so arik-so Feb 16, 2024

Choose a reason for hiding this comment

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

Rather than creating this variant, we could also add an enum inside the Forward variant that would describe the forwarding mechanism to be either based short_channel_id or outgoing_node_id.

/// 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
outgoing_node_id: PublicKey
},
Receive {
payment_data: Option<FinalOnionHopData>,
payment_metadata: Option<Vec<u8>>,
keysend_preimage: Option<PaymentPreimage>,
custom_tlvs: Vec<(u64, Vec<u8>)>,
sender_intended_htlc_amt_msat: u64,
cltv_expiry_height: u32,
trampoline_packet: Option<crate::onion_message::packet::Packet>
},
BlindedForward {
encrypted_tlvs: Vec<u8>,
Expand Down Expand Up @@ -2468,21 +2477,31 @@ impl Writeable for OutboundOnionPayload {
(6, short_channel_id, required)
});
},
Self::TrampolineForward { amt_to_forward, outgoing_cltv_value, outgoing_node_id } => {
_encode_varint_length_prefixed_tlv!(w, {
(2, HighZeroBytesDroppedBigSize(*amt_to_forward), required),
(4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
(14, outgoing_node_id, required)
});
},
Self::Receive {
ref payment_data, ref payment_metadata, ref keysend_preimage, sender_intended_htlc_amt_msat,
cltv_expiry_height, ref custom_tlvs,
cltv_expiry_height, ref trampoline_packet, ref custom_tlvs,
} => {
// We need to update [`ln::outbound_payment::RecipientOnionFields::with_custom_tlvs`]
// to reject any reserved types in the experimental range if new ones are ever
// standardized.
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();
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),
(8, payment_data, option),
(16, payment_metadata.as_ref().map(|m| WithoutLength(m)), option)
(16, payment_metadata.as_ref().map(|m| WithoutLength(m)), option),
(20, trampoline_packet, option)
}, custom_tlvs.iter());
},
Self::BlindedForward { encrypted_tlvs, intro_node_blinding_point } => {
Expand Down Expand Up @@ -3036,7 +3055,7 @@ mod tests {
use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket, CommonOpenChannelFields, CommonAcceptChannelFields};
use crate::ln::msgs::SocketAddress;
use crate::routing::gossip::{NodeAlias, NodeId};
use crate::util::ser::{Writeable, Readable, ReadableArgs, Hostname, TransactionU16LenLimited};
use crate::util::ser::{Writeable, Readable, ReadableArgs, Hostname, TransactionU16LenLimited, BigSize};
use crate::util::test_utils;

use bitcoin::hashes::hex::FromHex;
Expand All @@ -3060,6 +3079,7 @@ mod tests {
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
#[cfg(feature = "std")]
use crate::ln::msgs::SocketAddressParseError;
use crate::onion_message::packet::Packet;

#[test]
fn encoding_channel_reestablish() {
Expand Down Expand Up @@ -4208,6 +4228,7 @@ mod tests {
sender_intended_htlc_amt_msat: 0x0badf00d01020304,
cltv_expiry_height: 0xffffffff,
custom_tlvs: vec![],
trampoline_packet: None
};
let encoded_value = outbound_msg.encode();
let target_value = <Vec<u8>>::from_hex("1002080badf00d010203040404ffffffff").unwrap();
Expand Down Expand Up @@ -4236,6 +4257,7 @@ mod tests {
sender_intended_htlc_amt_msat: 0x0badf00d01020304,
cltv_expiry_height: 0xffffffff,
custom_tlvs: vec![],
trampoline_packet: None
};
let encoded_value = outbound_msg.encode();
let target_value = <Vec<u8>>::from_hex("3602080badf00d010203040404ffffffff082442424242424242424242424242424242424242424242424242424242424242421badca1f").unwrap();
Expand Down Expand Up @@ -4275,6 +4297,7 @@ mod tests {
custom_tlvs: bad_type_range_tlvs,
sender_intended_htlc_amt_msat: 0x0badf00d01020304,
cltv_expiry_height: 0xffffffff,
trampoline_packet: None
};
let encoded_value = msg.encode();
let node_signer = test_utils::TestKeysInterface::new(&[42; 32], Network::Testnet);
Expand Down Expand Up @@ -4307,6 +4330,7 @@ mod tests {
custom_tlvs: expected_custom_tlvs.clone(),
sender_intended_htlc_amt_msat: 0x0badf00d01020304,
cltv_expiry_height: 0xffffffff,
trampoline_packet: None
};
let encoded_value = msg.encode();
let target_value = <Vec<u8>>::from_hex("2e02080badf00d010203040404ffffffffff0000000146c6616b021234ff0000000146c6616f084242424242424242").unwrap();
Expand All @@ -4328,6 +4352,67 @@ mod tests {
} else { panic!(); }
}

#[test]
fn encoding_final_onion_hop_data_with_trampoline_packet() {
let secp_ctx = Secp256k1::new();
let (_private_key, public_key) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);

let compressed_public_key = public_key.serialize();
assert_eq!(compressed_public_key.len(), 33);

let trampoline_packet = Packet {
version: 0,
public_key,
hop_data: vec![1; 650], // this should be the standard encoded length
hmac: [2; 32],
};
let encoded_trampoline_packet = trampoline_packet.encode();
assert_eq!(encoded_trampoline_packet.len(), 716);

let msg = msgs::OutboundOnionPayload::Receive {
payment_data: None,
payment_metadata: None,
keysend_preimage: None,
custom_tlvs: Vec::new(),
sender_intended_htlc_amt_msat: 0x0badf00d01020304,
cltv_expiry_height: 0xffffffff,
trampoline_packet: Some(trampoline_packet),
};
let encoded_payload = msg.encode();

let trampoline_type_bytes = &encoded_payload[19..=19];
let mut trampoline_type_cursor = Cursor::new(trampoline_type_bytes);
let trampoline_type_big_size: BigSize = Readable::read(&mut trampoline_type_cursor).unwrap();
assert_eq!(trampoline_type_big_size.0, 20);

let trampoline_length_bytes = &encoded_payload[20..=22];
let mut trampoline_length_cursor = Cursor::new(trampoline_length_bytes);
let trampoline_length_big_size: BigSize = Readable::read(&mut trampoline_length_cursor).unwrap();
assert_eq!(trampoline_length_big_size.0, encoded_trampoline_packet.len() as u64);
}

#[test]
fn encoding_final_onion_hop_data_with_eclair_trampoline_packet() {
let public_key = PublicKey::from_slice(&<Vec<u8>>::from_hex("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619").unwrap()).unwrap();
let hop_data = <Vec<u8>>::from_hex("cff34152f3a36e52ca94e74927203a560392b9cc7ce3c45809c6be52166c24a595716880f95f178bf5b30ca63141f74db6e92795c6130877cfdac3d4bd3087ee73c65d627ddd709112a848cc99e303f3706509aa43ba7c8a88cba175fccf9a8f5016ef06d3b935dbb15196d7ce16dc1a7157845566901d7b2197e52cab4ce487014b14816e5805f9fcacb4f8f88b8ff176f1b94f6ce6b00bc43221130c17d20ef629db7c5f7eafaa166578c720619561dd14b3277db557ec7dcdb793771aef0f2f667cfdbeae3ac8d331c5994779dffb31e5fc0dbdedc0c592ca6d21c18e47fe3528d6975c19517d7e2ea8c5391cf17d0fe30c80913ed887234ccb48808f7ef9425bcd815c3b586210979e3bb286ef2851bf9ce04e28c40a203df98fd648d2f1936fd2f1def0e77eecb277229b4b682322371c0a1dbfcd723a991993df8cc1f2696b84b055b40a1792a29f710295a18fbd351b0f3ff34cd13941131b8278ba79303c89117120eea691738a9954908195143b039dbeed98f26a92585f3d15cf742c953799d3272e0545e9b744be9d3b4c").unwrap();
let hmac_vector = <Vec<u8>>::from_hex("bb079bfc4b35190eee9f59a1d7b41ba2f773179f322dafb4b1af900c289ebd6c").unwrap();
let mut hmac = [0; 32];
hmac.copy_from_slice(&hmac_vector);

let compressed_public_key = public_key.serialize();
assert_eq!(compressed_public_key.len(), 33);

let trampoline_packet = Packet {
version: 0,
public_key,
hop_data,
hmac,
};
let encoded_trampoline_packet = trampoline_packet.encode();
let expected_eclair_trampoline_packet = <Vec<u8>>::from_hex("0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619cff34152f3a36e52ca94e74927203a560392b9cc7ce3c45809c6be52166c24a595716880f95f178bf5b30ca63141f74db6e92795c6130877cfdac3d4bd3087ee73c65d627ddd709112a848cc99e303f3706509aa43ba7c8a88cba175fccf9a8f5016ef06d3b935dbb15196d7ce16dc1a7157845566901d7b2197e52cab4ce487014b14816e5805f9fcacb4f8f88b8ff176f1b94f6ce6b00bc43221130c17d20ef629db7c5f7eafaa166578c720619561dd14b3277db557ec7dcdb793771aef0f2f667cfdbeae3ac8d331c5994779dffb31e5fc0dbdedc0c592ca6d21c18e47fe3528d6975c19517d7e2ea8c5391cf17d0fe30c80913ed887234ccb48808f7ef9425bcd815c3b586210979e3bb286ef2851bf9ce04e28c40a203df98fd648d2f1936fd2f1def0e77eecb277229b4b682322371c0a1dbfcd723a991993df8cc1f2696b84b055b40a1792a29f710295a18fbd351b0f3ff34cd13941131b8278ba79303c89117120eea691738a9954908195143b039dbeed98f26a92585f3d15cf742c953799d3272e0545e9b744be9d3b4cbb079bfc4b35190eee9f59a1d7b41ba2f773179f322dafb4b1af900c289ebd6c").unwrap();
assert_eq!(encoded_trampoline_packet, expected_eclair_trampoline_packet);
}

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