@@ -71,6 +71,17 @@ pub struct Route {
7171 pub paths : Vec < Vec < RouteHop > > ,
7272}
7373
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+
7485const SERIALIZATION_VERSION : u8 = 1 ;
7586const MIN_SERIALIZATION_VERSION : u8 = 1 ;
7687
@@ -3425,6 +3436,7 @@ mod tests {
34253436 total_amount_paid_msat += path. last ( ) . unwrap ( ) . fee_msat ;
34263437 }
34273438 assert_eq ! ( total_amount_paid_msat, 200_000 ) ;
3439+ assert_eq ! ( route. get_total_fees( ) , 150_000 ) ;
34283440 }
34293441
34303442 }
@@ -3831,6 +3843,121 @@ mod tests {
38313843 }
38323844 }
38333845
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+
38343961 #[ cfg( not( feature = "no-std" ) ) ]
38353962 pub ( super ) fn random_init_seed ( ) -> u64 {
38363963 // Because the default HashMap in std pulls OS randomness, we can use it as a (bad) RNG.
0 commit comments