@@ -71,6 +71,26 @@ pub struct Route {
71
71
pub paths : Vec < Vec < RouteHop > > ,
72
72
}
73
73
74
+ impl Route {
75
+ /// Returns the total amount of fees paid on this Route.
76
+ /// This doesn't include any extra payment made to the recipient,
77
+ /// which can happen in excess of the amount passed to `get_route`'s `final_value_msat`.
78
+ pub fn get_total_fees ( & self ) -> u64 {
79
+ // Do not count last hop of each path since that's the full value of the payment
80
+ return self . paths . iter ( )
81
+ . flat_map ( |path| path. split_last ( ) . unwrap ( ) . 1 )
82
+ . map ( |hop| & hop. fee_msat )
83
+ . sum ( ) ;
84
+ }
85
+ /// Returns the total amount paid on this Route, excluding the fees.
86
+ pub fn get_total_amount ( & self ) -> u64 {
87
+ return self . paths . iter ( )
88
+ . map ( |path| path. split_last ( ) . unwrap ( ) . 0 )
89
+ . map ( |hop| & hop. fee_msat )
90
+ . sum ( ) ;
91
+ }
92
+ }
93
+
74
94
const SERIALIZATION_VERSION : u8 = 1 ;
75
95
const MIN_SERIALIZATION_VERSION : u8 = 1 ;
76
96
@@ -1191,7 +1211,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
1191
1211
1192
1212
#[ cfg( test) ]
1193
1213
mod tests {
1194
- use routing:: router:: { get_route, Route , RouteHint , RouteHintHop , RoutingFees } ;
1214
+ use routing:: router:: { get_route, Route , RouteHint , RouteHintHop , RouteHop , RoutingFees } ;
1195
1215
use routing:: network_graph:: { NetworkGraph , NetGraphMsgHandler } ;
1196
1216
use chain:: transaction:: OutPoint ;
1197
1217
use ln:: features:: { ChannelFeatures , InitFeatures , InvoiceFeatures , NodeFeatures } ;
@@ -3425,6 +3445,7 @@ mod tests {
3425
3445
total_amount_paid_msat += path. last ( ) . unwrap ( ) . fee_msat ;
3426
3446
}
3427
3447
assert_eq ! ( total_amount_paid_msat, 200_000 ) ;
3448
+ assert_eq ! ( route. get_total_fees( ) , 150_000 ) ;
3428
3449
}
3429
3450
3430
3451
}
@@ -3831,6 +3852,64 @@ mod tests {
3831
3852
}
3832
3853
}
3833
3854
3855
+ #[ test]
3856
+ fn total_fees_single_path ( ) {
3857
+ let route = Route {
3858
+ paths : vec ! [ vec![
3859
+ RouteHop {
3860
+ pubkey: PublicKey :: from_slice( & hex:: decode( "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619" ) . unwrap( ) [ ..] ) . unwrap( ) ,
3861
+ channel_features: ChannelFeatures :: empty( ) , node_features: NodeFeatures :: empty( ) ,
3862
+ short_channel_id: 0 , fee_msat: 100 , cltv_expiry_delta: 0 // Test vectors are garbage and not generateble from a RouteHop, we fill in payloads manually
3863
+ } ,
3864
+ RouteHop {
3865
+ pubkey: PublicKey :: from_slice( & hex:: decode( "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c" ) . unwrap( ) [ ..] ) . unwrap( ) ,
3866
+ channel_features: ChannelFeatures :: empty( ) , node_features: NodeFeatures :: empty( ) ,
3867
+ short_channel_id: 0 , fee_msat: 150 , cltv_expiry_delta: 0 // Test vectors are garbage and not generateble from a RouteHop, we fill in payloads manually
3868
+ } ,
3869
+ RouteHop {
3870
+ pubkey: PublicKey :: from_slice( & hex:: decode( "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007" ) . unwrap( ) [ ..] ) . unwrap( ) ,
3871
+ channel_features: ChannelFeatures :: empty( ) , node_features: NodeFeatures :: empty( ) ,
3872
+ short_channel_id: 0 , fee_msat: 225 , cltv_expiry_delta: 0 // Test vectors are garbage and not generateble from a RouteHop, we fill in payloads manually
3873
+ } ,
3874
+ ] ] ,
3875
+ } ;
3876
+
3877
+ assert_eq ! ( route. get_total_fees( ) , 250 ) ;
3878
+ assert_eq ! ( route. get_total_amount( ) , 225 ) ;
3879
+ }
3880
+
3881
+ #[ test]
3882
+ fn total_fees_multi_path ( ) {
3883
+ let route = Route {
3884
+ paths : vec ! [ vec![
3885
+ RouteHop {
3886
+ pubkey: PublicKey :: from_slice( & hex:: decode( "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619" ) . unwrap( ) [ ..] ) . unwrap( ) ,
3887
+ channel_features: ChannelFeatures :: empty( ) , node_features: NodeFeatures :: empty( ) ,
3888
+ short_channel_id: 0 , fee_msat: 100 , cltv_expiry_delta: 0 // Test vectors are garbage and not generateble from a RouteHop, we fill in payloads manually
3889
+ } ,
3890
+ RouteHop {
3891
+ pubkey: PublicKey :: from_slice( & hex:: decode( "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c" ) . unwrap( ) [ ..] ) . unwrap( ) ,
3892
+ channel_features: ChannelFeatures :: empty( ) , node_features: NodeFeatures :: empty( ) ,
3893
+ short_channel_id: 0 , fee_msat: 150 , cltv_expiry_delta: 0 // Test vectors are garbage and not generateble from a RouteHop, we fill in payloads manually
3894
+ } ,
3895
+ ] , vec![
3896
+ RouteHop {
3897
+ pubkey: PublicKey :: from_slice( & hex:: decode( "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619" ) . unwrap( ) [ ..] ) . unwrap( ) ,
3898
+ channel_features: ChannelFeatures :: empty( ) , node_features: NodeFeatures :: empty( ) ,
3899
+ short_channel_id: 0 , fee_msat: 100 , cltv_expiry_delta: 0 // Test vectors are garbage and not generateble from a RouteHop, we fill in payloads manually
3900
+ } ,
3901
+ RouteHop {
3902
+ pubkey: PublicKey :: from_slice( & hex:: decode( "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c" ) . unwrap( ) [ ..] ) . unwrap( ) ,
3903
+ channel_features: ChannelFeatures :: empty( ) , node_features: NodeFeatures :: empty( ) ,
3904
+ short_channel_id: 0 , fee_msat: 150 , cltv_expiry_delta: 0 // Test vectors are garbage and not generateble from a RouteHop, we fill in payloads manually
3905
+ } ,
3906
+ ] ] ,
3907
+ } ;
3908
+
3909
+ assert_eq ! ( route. get_total_fees( ) , 200 ) ;
3910
+ assert_eq ! ( route. get_total_amount( ) , 300 ) ;
3911
+ }
3912
+
3834
3913
#[ cfg( not( feature = "no-std" ) ) ]
3835
3914
pub ( super ) fn random_init_seed ( ) -> u64 {
3836
3915
// Because the default HashMap in std pulls OS randomness, we can use it as a (bad) RNG.
0 commit comments