@@ -71,6 +71,17 @@ pub struct Route {
71
71
pub paths : Vec < Vec < RouteHop > > ,
72
72
}
73
73
74
+ impl Route {
75
+ /// Returns the total amount of fees payed on this Route.
76
+ fn get_total_fees ( & self ) -> u64 {
77
+ // Do not count last hop of each path since that's the full value of the payment
78
+ return self . paths . iter ( )
79
+ . flat_map ( |path| path. split_last ( ) . unwrap ( ) . 1 )
80
+ . map ( |hop| & hop. fee_msat )
81
+ . sum ( ) ;
82
+ }
83
+ }
84
+
74
85
const SERIALIZATION_VERSION : u8 = 1 ;
75
86
const MIN_SERIALIZATION_VERSION : u8 = 1 ;
76
87
@@ -3425,6 +3436,7 @@ mod tests {
3425
3436
total_amount_paid_msat += path. last ( ) . unwrap ( ) . fee_msat ;
3426
3437
}
3427
3438
assert_eq ! ( total_amount_paid_msat, 200_000 ) ;
3439
+ assert_eq ! ( route. get_total_fees( ) , 150_000 ) ;
3428
3440
}
3429
3441
3430
3442
}
@@ -3831,6 +3843,121 @@ mod tests {
3831
3843
}
3832
3844
}
3833
3845
3846
+ // Tweaked from available_liquidity_last_hop_test
3847
+ #[ test]
3848
+ fn total_fees_single_path ( ) {
3849
+ // Check that total fees in single path payment are calculated properly
3850
+ let ( secp_ctx, net_graph_msg_handler, _, logger) = build_graph ( ) ;
3851
+ let ( our_privkey, our_id, privkeys, nodes) = get_nodes ( & secp_ctx) ;
3852
+
3853
+ // Path via {node7, node2, node4} is channels {12, 13, 6, 11}.
3854
+ // {12, 13, 11} have the capacities of 100, {6} has a capacity of 50.
3855
+ // Total capacity: 50 sats.
3856
+ // Fee in first channel does not count since that's opened by the originating node.
3857
+ // So, only the fees of the last 3 channels count towards total fees.
3858
+
3859
+ // Disable other potential paths.
3860
+ update_channel ( & net_graph_msg_handler, & secp_ctx, & our_privkey, UnsignedChannelUpdate {
3861
+ chain_hash : genesis_block ( Network :: Testnet ) . header . block_hash ( ) ,
3862
+ short_channel_id : 2 ,
3863
+ timestamp : 2 ,
3864
+ flags : 2 ,
3865
+ cltv_expiry_delta : 0 ,
3866
+ htlc_minimum_msat : 0 ,
3867
+ htlc_maximum_msat : OptionalField :: Present ( 100_000 ) ,
3868
+ fee_base_msat : 0 ,
3869
+ fee_proportional_millionths : 0 ,
3870
+ excess_data : Vec :: new ( )
3871
+ } ) ;
3872
+ update_channel ( & net_graph_msg_handler, & secp_ctx, & privkeys[ 2 ] , UnsignedChannelUpdate {
3873
+ chain_hash : genesis_block ( Network :: Testnet ) . header . block_hash ( ) ,
3874
+ short_channel_id : 7 ,
3875
+ timestamp : 2 ,
3876
+ flags : 2 ,
3877
+ cltv_expiry_delta : 0 ,
3878
+ htlc_minimum_msat : 0 ,
3879
+ htlc_maximum_msat : OptionalField :: Present ( 100_000 ) ,
3880
+ fee_base_msat : 0 ,
3881
+ fee_proportional_millionths : 0 ,
3882
+ excess_data : Vec :: new ( )
3883
+ } ) ;
3884
+
3885
+ // Limit capacities
3886
+
3887
+ update_channel ( & net_graph_msg_handler, & secp_ctx, & our_privkey, UnsignedChannelUpdate {
3888
+ chain_hash : genesis_block ( Network :: Testnet ) . header . block_hash ( ) ,
3889
+ short_channel_id : 12 ,
3890
+ timestamp : 2 ,
3891
+ flags : 0 ,
3892
+ cltv_expiry_delta : 0 ,
3893
+ htlc_minimum_msat : 0 ,
3894
+ htlc_maximum_msat : OptionalField :: Present ( 100_000 ) ,
3895
+ fee_base_msat : 210 ,
3896
+ fee_proportional_millionths : 0 ,
3897
+ excess_data : Vec :: new ( )
3898
+ } ) ;
3899
+ update_channel ( & net_graph_msg_handler, & secp_ctx, & privkeys[ 7 ] , UnsignedChannelUpdate {
3900
+ chain_hash : genesis_block ( Network :: Testnet ) . header . block_hash ( ) ,
3901
+ short_channel_id : 13 ,
3902
+ timestamp : 2 ,
3903
+ flags : 0 ,
3904
+ cltv_expiry_delta : 0 ,
3905
+ htlc_minimum_msat : 0 ,
3906
+ htlc_maximum_msat : OptionalField :: Present ( 100_000 ) ,
3907
+ fee_base_msat : 220 ,
3908
+ fee_proportional_millionths : 0 ,
3909
+ excess_data : Vec :: new ( )
3910
+ } ) ;
3911
+
3912
+ update_channel ( & net_graph_msg_handler, & secp_ctx, & privkeys[ 2 ] , UnsignedChannelUpdate {
3913
+ chain_hash : genesis_block ( Network :: Testnet ) . header . block_hash ( ) ,
3914
+ short_channel_id : 6 ,
3915
+ timestamp : 2 ,
3916
+ flags : 0 ,
3917
+ cltv_expiry_delta : 0 ,
3918
+ htlc_minimum_msat : 0 ,
3919
+ htlc_maximum_msat : OptionalField :: Present ( 50_000 ) ,
3920
+ fee_base_msat : 280 ,
3921
+ fee_proportional_millionths : 0 ,
3922
+ excess_data : Vec :: new ( )
3923
+ } ) ;
3924
+ update_channel ( & net_graph_msg_handler, & secp_ctx, & privkeys[ 4 ] , UnsignedChannelUpdate {
3925
+ chain_hash : genesis_block ( Network :: Testnet ) . header . block_hash ( ) ,
3926
+ short_channel_id : 11 ,
3927
+ timestamp : 2 ,
3928
+ flags : 0 ,
3929
+ cltv_expiry_delta : 0 ,
3930
+ htlc_minimum_msat : 0 ,
3931
+ htlc_maximum_msat : OptionalField :: Present ( 100_000 ) ,
3932
+ fee_base_msat : 290 ,
3933
+ fee_proportional_millionths : 0 ,
3934
+ excess_data : Vec :: new ( )
3935
+ } ) ;
3936
+
3937
+ {
3938
+ // Now, attempt to route 49 sats (just a bit below the capacity).
3939
+ let route = get_route ( & our_id, & net_graph_msg_handler. network_graph . read ( ) . unwrap ( ) , & nodes[ 3 ] ,
3940
+ Some ( InvoiceFeatures :: known ( ) ) , None , & Vec :: new ( ) , 49_000 , 42 , Arc :: clone ( & logger) ) . unwrap ( ) ;
3941
+ assert_eq ! ( route. paths. len( ) , 1 ) ;
3942
+
3943
+ let mut total_value_transferred_msat = 0 ;
3944
+ let mut total_paid_msat = 0 ;
3945
+ for path in & route. paths {
3946
+ assert_eq ! ( path. len( ) , 4 ) ;
3947
+ assert_eq ! ( path. last( ) . unwrap( ) . pubkey, nodes[ 3 ] ) ;
3948
+ total_value_transferred_msat += path. last ( ) . unwrap ( ) . fee_msat ;
3949
+ for hop in path {
3950
+ total_paid_msat += hop. fee_msat ;
3951
+ }
3952
+ }
3953
+ // If we paid fee, this would be higher.
3954
+ assert_eq ! ( total_value_transferred_msat, 49_000 ) ;
3955
+ let total_fees_paid = total_paid_msat - total_value_transferred_msat;
3956
+ assert_eq ! ( total_fees_paid, 790 ) ;
3957
+ assert_eq ! ( route. get_total_fees( ) , 790 ) ;
3958
+ }
3959
+ }
3960
+
3834
3961
#[ cfg( not( feature = "no-std" ) ) ]
3835
3962
pub ( super ) fn random_init_seed ( ) -> u64 {
3836
3963
// Because the default HashMap in std pulls OS randomness, we can use it as a (bad) RNG.
0 commit comments