@@ -1746,9 +1746,9 @@ pub struct FinalOnionHopData {
17461746
17471747mod  fuzzy_internal_msgs { 
17481748	use  bitcoin:: secp256k1:: PublicKey ; 
1749- 	use  crate :: blinded_path:: payment:: { PaymentConstraints ,  PaymentContext ,  PaymentRelay } ; 
1749+ 	use  crate :: blinded_path:: payment:: { BlindedPaymentPath ,   PaymentConstraints ,  PaymentContext ,  PaymentRelay } ; 
17501750	use  crate :: types:: payment:: { PaymentPreimage ,  PaymentSecret } ; 
1751- 	use  crate :: types:: features:: BlindedHopFeatures ; 
1751+ 	use  crate :: types:: features:: { BlindedHopFeatures ,   Bolt12InvoiceFeatures } ; 
17521752	use  super :: { FinalOnionHopData ,  TrampolineOnionPacket } ; 
17531753
17541754	#[ allow( unused_imports) ]  
@@ -1830,14 +1830,41 @@ mod fuzzy_internal_msgs {
18301830		} 
18311831	} 
18321832
1833- 	pub ( crate )  enum  OutboundTrampolinePayload  { 
1833+ 	pub ( crate )  enum  OutboundTrampolinePayload < ' a >  { 
18341834		#[ allow( unused) ]  
18351835		Forward  { 
18361836			/// The value, in msat, of the payment after this hop's fee is deducted. 
18371837 			amt_to_forward :  u64 , 
18381838			outgoing_cltv_value :  u32 , 
1839- 			/// The node id to which the trampoline node must find a route 
1839+ 			/// The node id to which the trampoline node must find a route.  
18401840 			outgoing_node_id :  PublicKey , 
1841+ 		} , 
1842+ 		#[ allow( unused) ]  
1843+ 		/// This is the last Trampoline hop, whereupon the Trampoline forward mechanism is exited, 
1844+  		/// and payment data is relayed using non-Trampoline blinded hops 
1845+  		LegacyBlindedPathEntry  { 
1846+ 			/// The value, in msat, of the payment after this hop's fee is deducted. 
1847+  			amt_to_forward :  u64 , 
1848+ 			outgoing_cltv_value :  u32 , 
1849+ 			/// List of blinded path options the last trampoline hop may choose to route through. 
1850+  			payment_paths :  Vec < BlindedPaymentPath > , 
1851+ 			/// If applicable, features of the BOLT12 invoice being paid. 
1852+  			invoice_features :  Option < Bolt12InvoiceFeatures > , 
1853+ 		} , 
1854+ 		#[ allow( unused) ]  
1855+ 		BlindedForward  { 
1856+ 			encrypted_tlvs :  & ' a  Vec < u8 > , 
1857+ 			intro_node_blinding_point :  Option < PublicKey > , 
1858+ 		} , 
1859+ 		#[ allow( unused) ]  
1860+ 		BlindedReceive  { 
1861+ 			sender_intended_htlc_amt_msat :  u64 , 
1862+ 			total_msat :  u64 , 
1863+ 			cltv_expiry_height :  u32 , 
1864+ 			encrypted_tlvs :  & ' a  Vec < u8 > , 
1865+ 			intro_node_blinding_point :  Option < PublicKey > ,  // Set if the introduction node of the blinded path is the final node 
1866+ 			keysend_preimage :  Option < PaymentPreimage > , 
1867+ 			custom_tlvs :  & ' a  Vec < ( u64 ,  Vec < u8 > ) > , 
18411868		} 
18421869	} 
18431870
@@ -2754,7 +2781,7 @@ impl<'a> Writeable for OutboundOnionPayload<'a> {
27542781	} 
27552782} 
27562783
2757- impl  Writeable  for  OutboundTrampolinePayload  { 
2784+ impl < ' a >  Writeable  for  OutboundTrampolinePayload < ' a >  { 
27582785	fn  write < W :  Writer > ( & self ,  w :  & mut  W )  -> Result < ( ) ,  io:: Error >  { 
27592786		match  self  { 
27602787			Self :: Forward  {  amt_to_forward,  outgoing_cltv_value,  outgoing_node_id }  => { 
@@ -2763,6 +2790,41 @@ impl Writeable for OutboundTrampolinePayload {
27632790					( 4 ,  HighZeroBytesDroppedBigSize ( * outgoing_cltv_value) ,  required) , 
27642791					( 14 ,  outgoing_node_id,  required) 
27652792				} ) ; 
2793+ 			} , 
2794+ 			Self :: LegacyBlindedPathEntry  {  amt_to_forward,  outgoing_cltv_value,  payment_paths,  invoice_features }  => { 
2795+ 				let  mut  blinded_path_serialization = [ 0u8 ;  2048 ] ;  // Fixed-length buffer on the stack 
2796+ 				let  serialization_length = { 
2797+ 					let  buffer_size = blinded_path_serialization. len ( ) ; 
2798+ 					let  mut  blinded_path_slice = & mut  blinded_path_serialization[ ..] ; 
2799+ 					for  current_payment_path in  payment_paths { 
2800+ 						current_payment_path. inner_blinded_path ( ) . write ( & mut  blinded_path_slice) ?; 
2801+ 						current_payment_path. payinfo . write ( & mut  blinded_path_slice) ?; 
2802+ 					} 
2803+ 					buffer_size - blinded_path_slice. len ( ) 
2804+ 				} ; 
2805+ 				let  blinded_path_serialization = & blinded_path_serialization[ ..serialization_length] ; 
2806+ 				_encode_varint_length_prefixed_tlv ! ( w,  { 
2807+ 					( 2 ,  HighZeroBytesDroppedBigSize ( * amt_to_forward) ,  required) , 
2808+ 					( 4 ,  HighZeroBytesDroppedBigSize ( * outgoing_cltv_value) ,  required) , 
2809+ 					( 21 ,  invoice_features. as_ref( ) . map( |m| WithoutLength ( m) ) ,  option) , 
2810+ 					( 22 ,  WithoutLength ( blinded_path_serialization) ,  required) 
2811+ 				} ) ; 
2812+ 			} , 
2813+ 			Self :: BlindedForward  {  encrypted_tlvs,  intro_node_blinding_point}  => { 
2814+ 				_encode_varint_length_prefixed_tlv ! ( w,  { 
2815+ 					( 10 ,  * * encrypted_tlvs,  required_vec) , 
2816+ 					( 12 ,  intro_node_blinding_point,  option) 
2817+ 				} ) ; 
2818+ 			} , 
2819+ 			Self :: BlindedReceive  {  sender_intended_htlc_amt_msat,  total_msat,  cltv_expiry_height,  encrypted_tlvs,  intro_node_blinding_point,  keysend_preimage,  custom_tlvs }  => { 
2820+ 				_encode_varint_length_prefixed_tlv ! ( w,  { 
2821+ 					( 2 ,  HighZeroBytesDroppedBigSize ( * sender_intended_htlc_amt_msat) ,  required) , 
2822+ 					( 4 ,  HighZeroBytesDroppedBigSize ( * cltv_expiry_height) ,  required) , 
2823+ 					( 10 ,  * * encrypted_tlvs,  required_vec) , 
2824+ 					( 12 ,  intro_node_blinding_point,  option) , 
2825+ 					( 18 ,  HighZeroBytesDroppedBigSize ( * total_msat) ,  required) , 
2826+ 					( 20 ,  keysend_preimage,  option) 
2827+ 				} ,  custom_tlvs. iter( ) ) ; 
27662828			} 
27672829		} 
27682830		Ok ( ( ) ) 
@@ -3302,7 +3364,7 @@ mod tests {
33023364	use  crate :: ln:: types:: ChannelId ; 
33033365	use  crate :: types:: payment:: { PaymentPreimage ,  PaymentHash ,  PaymentSecret } ; 
33043366	use  crate :: types:: features:: { ChannelFeatures ,  ChannelTypeFeatures ,  InitFeatures ,  NodeFeatures } ; 
3305- 	use  crate :: ln:: msgs:: { self ,  FinalOnionHopData ,  OnionErrorPacket ,  CommonOpenChannelFields ,  CommonAcceptChannelFields ,  TrampolineOnionPacket } ; 
3367+ 	use  crate :: ln:: msgs:: { self ,  FinalOnionHopData ,  OnionErrorPacket ,  CommonOpenChannelFields ,  CommonAcceptChannelFields ,  OutboundTrampolinePayload ,   TrampolineOnionPacket } ; 
33063368	use  crate :: ln:: msgs:: SocketAddress ; 
33073369	use  crate :: routing:: gossip:: { NodeAlias ,  NodeId } ; 
33083370	use  crate :: util:: ser:: { BigSize ,  FixedLengthReader ,  Hostname ,  LengthReadable ,  Readable ,  ReadableArgs ,  TransactionU16LenLimited ,  Writeable } ; 
@@ -3328,6 +3390,8 @@ mod tests {
33283390
33293391	#[ cfg( feature = "std" ) ]  
33303392	use  std:: net:: { Ipv4Addr ,  Ipv6Addr ,  SocketAddr ,  SocketAddrV4 ,  SocketAddrV6 ,  ToSocketAddrs } ; 
3393+ 	use  types:: features:: { BlindedHopFeatures ,  Bolt12InvoiceFeatures } ; 
3394+ 	use  crate :: blinded_path:: payment:: { BlindedPayInfo ,  BlindedPaymentPath } ; 
33313395	#[ cfg( feature = "std" ) ]  
33323396	use  crate :: ln:: msgs:: SocketAddressParseError ; 
33333397
@@ -4675,6 +4739,58 @@ mod tests {
46754739		assert_eq ! ( encoded_trampoline_packet,  expected_eclair_trampoline_packet) ; 
46764740	} 
46774741
4742+ 	#[ test]  
4743+ 	fn  encoding_outbound_trampoline_payload ( )  { 
4744+ 		let  mut  trampoline_features = Bolt12InvoiceFeatures :: empty ( ) ; 
4745+ 		trampoline_features. set_basic_mpp_optional ( ) ; 
4746+ 		let  introduction_node = PublicKey :: from_slice ( & <Vec < u8 > >:: from_hex ( "032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991" ) . unwrap ( ) ) . unwrap ( ) ; 
4747+ 		let  blinding_point = PublicKey :: from_slice ( & <Vec < u8 > >:: from_hex ( "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619" ) . unwrap ( ) ) . unwrap ( ) ; 
4748+ 		let  trampoline_payload = OutboundTrampolinePayload :: LegacyBlindedPathEntry  { 
4749+ 			amt_to_forward :  150_000_000 , 
4750+ 			outgoing_cltv_value :  800_000 , 
4751+ 			payment_paths :  vec ! [ 
4752+ 				BlindedPaymentPath :: from_raw( 
4753+ 					introduction_node, 
4754+ 					blinding_point, 
4755+ 					vec![ ] , 
4756+ 					BlindedPayInfo { 
4757+ 						fee_base_msat:  500 , 
4758+ 						fee_proportional_millionths:  1_000 , 
4759+ 						cltv_expiry_delta:  36 , 
4760+ 						htlc_minimum_msat:  1 , 
4761+ 						htlc_maximum_msat:  500_000_000 , 
4762+ 						features:  BlindedHopFeatures :: empty( ) , 
4763+ 					} 
4764+ 				) 
4765+ 			] , 
4766+ 			invoice_features :  Some ( trampoline_features) , 
4767+ 		} ; 
4768+ 		let  serialized_payload = trampoline_payload. encode ( ) . to_lower_hex_string ( ) ; 
4769+ 		assert_eq ! ( serialized_payload,  "71020408f0d18004030c35001503020000165f032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e66868099102eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f28368661900000001f4000003e800240000000000000001000000001dcd65000000" ) ; 
4770+ 	} 
4771+ 
4772+ 	#[ test]  
4773+ 	fn  encode_trampoline_blinded_path_payload ( )  { 
4774+ 		let  trampoline_payload_eve = OutboundTrampolinePayload :: BlindedReceive  { 
4775+ 			sender_intended_htlc_amt_msat :  150_000_000 , 
4776+ 			total_msat :  150_000_000 , 
4777+ 			cltv_expiry_height :  800_000 , 
4778+ 			encrypted_tlvs :  & <Vec < u8 > >:: from_hex ( "bcd747394fbd4d99588da075a623316e15a576df5bc785cccc7cd6ec7b398acce6faf520175f9ec920f2ef261cdb83dc28cc3a0eeb970107b3306489bf771ef5b1213bca811d345285405861d08a655b6c237fa247a8b4491beee20c878a60e9816492026d8feb9dafa84585b253978db6a0aa2945df5ef445c61e801fb82f43d5f00716baf9fc9b3de50bc22950a36bda8fc27bfb1242e5860c7e687438d4133e058770361a19b6c271a2a07788d34dccc27e39b9829b061a4d960eac4a2c2b0f4de506c24f9af3868c0aff6dda27281c" ) . unwrap ( ) , 
4779+ 			intro_node_blinding_point :  None , 
4780+ 			keysend_preimage :  None , 
4781+ 			custom_tlvs :  & vec ! [ ] , 
4782+ 		} ; 
4783+ 		let  eve_payload = trampoline_payload_eve. encode ( ) . to_lower_hex_string ( ) ; 
4784+ 		assert_eq ! ( eve_payload,  "e4020408f0d18004030c35000ad1bcd747394fbd4d99588da075a623316e15a576df5bc785cccc7cd6ec7b398acce6faf520175f9ec920f2ef261cdb83dc28cc3a0eeb970107b3306489bf771ef5b1213bca811d345285405861d08a655b6c237fa247a8b4491beee20c878a60e9816492026d8feb9dafa84585b253978db6a0aa2945df5ef445c61e801fb82f43d5f00716baf9fc9b3de50bc22950a36bda8fc27bfb1242e5860c7e687438d4133e058770361a19b6c271a2a07788d34dccc27e39b9829b061a4d960eac4a2c2b0f4de506c24f9af3868c0aff6dda27281c120408f0d180" ) ; 
4785+ 
4786+ 		let  trampoline_payload_dave = OutboundTrampolinePayload :: BlindedForward  { 
4787+ 			encrypted_tlvs :  & <Vec < u8 > >:: from_hex ( "0ccf3c8a58deaa603f657ee2a5ed9d604eb5c8ca1e5f801989afa8f3ea6d789bbdde2c7e7a1ef9ca8c38d2c54760febad8446d3f273ddb537569ef56613846ccd3aba78a" ) . unwrap ( ) , 
4788+ 			intro_node_blinding_point :  Some ( PublicKey :: from_slice ( & <Vec < u8 > >:: from_hex ( "02988face71e92c345a068f740191fd8e53be14f0bb957ef730d3c5f76087b960e" ) . unwrap ( ) ) . unwrap ( ) ) , 
4789+ 		} ; 
4790+ 		let  dave_payload = trampoline_payload_dave. encode ( ) . to_lower_hex_string ( ) ; 
4791+ 		assert_eq ! ( dave_payload,  "690a440ccf3c8a58deaa603f657ee2a5ed9d604eb5c8ca1e5f801989afa8f3ea6d789bbdde2c7e7a1ef9ca8c38d2c54760febad8446d3f273ddb537569ef56613846ccd3aba78a0c2102988face71e92c345a068f740191fd8e53be14f0bb957ef730d3c5f76087b960e" ) 
4792+ 	} 
4793+ 
46784794	#[ test]  
46794795	fn  query_channel_range_end_blocknum ( )  { 
46804796		let  tests:  Vec < ( u32 ,  u32 ,  u32 ) >  = vec ! [ 
0 commit comments