@@ -357,14 +357,25 @@ impl Writeable for Route {
357
357
fn write < W : crate :: util:: ser:: Writer > ( & self , writer : & mut W ) -> Result < ( ) , io:: Error > {
358
358
write_ver_prefix ! ( writer, SERIALIZATION_VERSION , MIN_SERIALIZATION_VERSION ) ;
359
359
( self . paths . len ( ) as u64 ) . write ( writer) ?;
360
+ let mut blinded_tails = Vec :: new ( ) ;
360
361
for path in self . paths . iter ( ) {
361
362
( path. hops . len ( ) as u8 ) . write ( writer) ?;
362
- for hop in path. hops . iter ( ) {
363
+ for ( idx , hop) in path. hops . iter ( ) . enumerate ( ) {
363
364
hop. write ( writer) ?;
365
+ if let Some ( blinded_tail) = & path. blinded_tail {
366
+ if blinded_tails. is_empty ( ) {
367
+ blinded_tails = Vec :: with_capacity ( path. hops . len ( ) ) ;
368
+ for _ in 0 ..idx {
369
+ blinded_tails. push ( None ) ;
370
+ }
371
+ }
372
+ blinded_tails. push ( Some ( blinded_tail) ) ;
373
+ } else if !blinded_tails. is_empty ( ) { blinded_tails. push ( None ) ; }
364
374
}
365
375
}
366
376
write_tlv_fields ! ( writer, {
367
377
( 1 , self . payment_params, option) ,
378
+ ( 2 , blinded_tails, optional_vec) ,
368
379
} ) ;
369
380
Ok ( ( ) )
370
381
}
@@ -388,10 +399,17 @@ impl Readable for Route {
388
399
cmp:: min ( min_final_cltv_expiry_delta, hops. last ( ) . unwrap ( ) . cltv_expiry_delta ) ;
389
400
paths. push ( Path { hops, blinded_tail : None } ) ;
390
401
}
391
- let mut payment_params = None ;
392
- read_tlv_fields ! ( reader, {
402
+ _init_and_read_tlv_fields ! ( reader, {
393
403
( 1 , payment_params, ( option: ReadableArgs , min_final_cltv_expiry_delta) ) ,
404
+ ( 2 , blinded_tails, optional_vec) ,
394
405
} ) ;
406
+ let blinded_tails = blinded_tails. unwrap_or ( Vec :: new ( ) ) ;
407
+ if blinded_tails. len ( ) != 0 {
408
+ if blinded_tails. len ( ) != paths. len ( ) { return Err ( DecodeError :: InvalidValue ) }
409
+ for ( mut path, blinded_tail_opt) in paths. iter_mut ( ) . zip ( blinded_tails. into_iter ( ) ) {
410
+ path. blinded_tail = blinded_tail_opt;
411
+ }
412
+ }
395
413
Ok ( Route { paths, payment_params } )
396
414
}
397
415
}
@@ -2244,10 +2262,11 @@ fn build_route_from_hops_internal<L: Deref>(
2244
2262
2245
2263
#[ cfg( test) ]
2246
2264
mod tests {
2265
+ use crate :: blinded_path:: { BlindedHop , BlindedPath } ;
2247
2266
use crate :: routing:: gossip:: { NetworkGraph , P2PGossipSync , NodeId , EffectiveCapacity } ;
2248
2267
use crate :: routing:: utxo:: UtxoResult ;
2249
2268
use crate :: routing:: router:: { get_route, build_route_from_hops_internal, add_random_cltv_offset, default_node_features,
2250
- Path , PaymentParameters , Route , RouteHint , RouteHintHop , RouteHop , RoutingFees ,
2269
+ BlindedTail , Path , PaymentParameters , Route , RouteHint , RouteHintHop , RouteHop , RoutingFees ,
2251
2270
DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA , MAX_PATH_LENGTH_ESTIMATE } ;
2252
2271
use crate :: routing:: scoring:: { ChannelUsage , FixedPenaltyScorer , Score , ProbabilisticScorer , ProbabilisticScoringParameters } ;
2253
2272
use crate :: routing:: test_utils:: { add_channel, add_or_update_node, build_graph, build_line_graph, id_to_feature_flags, get_nodes, update_channel} ;
@@ -2259,8 +2278,9 @@ mod tests {
2259
2278
use crate :: util:: config:: UserConfig ;
2260
2279
use crate :: util:: test_utils as ln_test_utils;
2261
2280
use crate :: util:: chacha20:: ChaCha20 ;
2281
+ use crate :: util:: ser:: { Readable , Writeable } ;
2262
2282
#[ cfg( c_bindings) ]
2263
- use crate :: util:: ser:: { Writeable , Writer } ;
2283
+ use crate :: util:: ser:: Writer ;
2264
2284
2265
2285
use bitcoin:: hashes:: Hash ;
2266
2286
use bitcoin:: network:: constants:: Network ;
@@ -2274,6 +2294,7 @@ mod tests {
2274
2294
use bitcoin:: secp256k1:: { PublicKey , SecretKey } ;
2275
2295
use bitcoin:: secp256k1:: Secp256k1 ;
2276
2296
2297
+ use crate :: io:: Cursor ;
2277
2298
use crate :: prelude:: * ;
2278
2299
use crate :: sync:: Arc ;
2279
2300
@@ -5744,6 +5765,68 @@ mod tests {
5744
5765
let route = get_route ( & our_id, & payment_params, & network_graph. read_only ( ) , None , 100 , 42 , Arc :: clone ( & logger) , & scorer, & random_seed_bytes) ;
5745
5766
assert ! ( route. is_ok( ) ) ;
5746
5767
}
5768
+
5769
+ #[ test]
5770
+ fn blinded_route_ser ( ) {
5771
+ let blinded_path_1 = BlindedPath {
5772
+ introduction_node_id : ln_test_utils:: pubkey ( 42 ) ,
5773
+ blinding_point : ln_test_utils:: pubkey ( 43 ) ,
5774
+ blinded_hops : vec ! [
5775
+ BlindedHop { blinded_node_id: ln_test_utils:: pubkey( 44 ) , encrypted_payload: Vec :: new( ) } ,
5776
+ BlindedHop { blinded_node_id: ln_test_utils:: pubkey( 45 ) , encrypted_payload: Vec :: new( ) }
5777
+ ] ,
5778
+ } ;
5779
+ let blinded_path_2 = BlindedPath {
5780
+ introduction_node_id : ln_test_utils:: pubkey ( 46 ) ,
5781
+ blinding_point : ln_test_utils:: pubkey ( 47 ) ,
5782
+ blinded_hops : vec ! [
5783
+ BlindedHop { blinded_node_id: ln_test_utils:: pubkey( 48 ) , encrypted_payload: Vec :: new( ) } ,
5784
+ BlindedHop { blinded_node_id: ln_test_utils:: pubkey( 49 ) , encrypted_payload: Vec :: new( ) }
5785
+ ] ,
5786
+ } ;
5787
+ // (De)serialize a Route with 1 blinded path out of two total paths.
5788
+ let mut route = Route { paths : vec ! [ Path {
5789
+ hops: vec![ RouteHop {
5790
+ pubkey: ln_test_utils:: pubkey( 50 ) ,
5791
+ node_features: NodeFeatures :: empty( ) ,
5792
+ short_channel_id: 42 ,
5793
+ channel_features: ChannelFeatures :: empty( ) ,
5794
+ fee_msat: 100 ,
5795
+ cltv_expiry_delta: 0 ,
5796
+ } ] ,
5797
+ blinded_tail: Some ( BlindedTail {
5798
+ hops: blinded_path_1. blinded_hops,
5799
+ blinding_point: blinded_path_1. blinding_point,
5800
+ final_cltv_expiry_delta: 40 ,
5801
+ final_value_msat: 100 ,
5802
+ } ) } , Path {
5803
+ hops: vec![ RouteHop {
5804
+ pubkey: ln_test_utils:: pubkey( 51 ) ,
5805
+ node_features: NodeFeatures :: empty( ) ,
5806
+ short_channel_id: 43 ,
5807
+ channel_features: ChannelFeatures :: empty( ) ,
5808
+ fee_msat: 100 ,
5809
+ cltv_expiry_delta: 0 ,
5810
+ } ] , blinded_tail: None } ] ,
5811
+ payment_params : None ,
5812
+ } ;
5813
+ let encoded_route = route. encode ( ) ;
5814
+ let decoded_route: Route = Readable :: read ( & mut Cursor :: new ( & encoded_route[ ..] ) ) . unwrap ( ) ;
5815
+ assert_eq ! ( decoded_route. paths[ 0 ] . blinded_tail, route. paths[ 0 ] . blinded_tail) ;
5816
+ assert_eq ! ( decoded_route. paths[ 1 ] . blinded_tail, route. paths[ 1 ] . blinded_tail) ;
5817
+
5818
+ // (De)serialize a Route with two paths, each containing a blinded tail.
5819
+ route. paths [ 1 ] . blinded_tail = Some ( BlindedTail {
5820
+ hops : blinded_path_2. blinded_hops ,
5821
+ blinding_point : blinded_path_2. blinding_point ,
5822
+ final_cltv_expiry_delta : 41 ,
5823
+ final_value_msat : 101 ,
5824
+ } ) ;
5825
+ let encoded_route = route. encode ( ) ;
5826
+ let decoded_route: Route = Readable :: read ( & mut Cursor :: new ( & encoded_route[ ..] ) ) . unwrap ( ) ;
5827
+ assert_eq ! ( decoded_route. paths[ 0 ] . blinded_tail, route. paths[ 0 ] . blinded_tail) ;
5828
+ assert_eq ! ( decoded_route. paths[ 1 ] . blinded_tail, route. paths[ 1 ] . blinded_tail) ;
5829
+ }
5747
5830
}
5748
5831
5749
5832
#[ cfg( all( test, not( feature = "no-std" ) ) ) ]
0 commit comments