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