@@ -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
@@ -1245,7 +1265,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
1245
1265
1246
1266
#[ cfg( test) ]
1247
1267
mod tests {
1248
- use routing:: router:: { get_route, Route , RouteHint , RouteHintHop , RoutingFees } ;
1268
+ use routing:: router:: { get_route, Route , RouteHint , RouteHintHop , RouteHop , RoutingFees } ;
1249
1269
use routing:: network_graph:: { NetworkGraph , NetGraphMsgHandler } ;
1250
1270
use chain:: transaction:: OutPoint ;
1251
1271
use ln:: features:: { ChannelFeatures , InitFeatures , InvoiceFeatures , NodeFeatures } ;
@@ -3791,6 +3811,7 @@ mod tests {
3791
3811
total_amount_paid_msat += path. last ( ) . unwrap ( ) . fee_msat ;
3792
3812
}
3793
3813
assert_eq ! ( total_amount_paid_msat, 200_000 ) ;
3814
+ assert_eq ! ( route. get_total_fees( ) , 150_000 ) ;
3794
3815
}
3795
3816
3796
3817
}
@@ -4198,6 +4219,64 @@ mod tests {
4198
4219
}
4199
4220
}
4200
4221
4222
+ #[ test]
4223
+ fn total_fees_single_path ( ) {
4224
+ let route = Route {
4225
+ paths : vec ! [ vec![
4226
+ RouteHop {
4227
+ pubkey: PublicKey :: from_slice( & hex:: decode( "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619" ) . unwrap( ) [ ..] ) . unwrap( ) ,
4228
+ channel_features: ChannelFeatures :: empty( ) , node_features: NodeFeatures :: empty( ) ,
4229
+ 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
4230
+ } ,
4231
+ RouteHop {
4232
+ pubkey: PublicKey :: from_slice( & hex:: decode( "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c" ) . unwrap( ) [ ..] ) . unwrap( ) ,
4233
+ channel_features: ChannelFeatures :: empty( ) , node_features: NodeFeatures :: empty( ) ,
4234
+ 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
4235
+ } ,
4236
+ RouteHop {
4237
+ pubkey: PublicKey :: from_slice( & hex:: decode( "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007" ) . unwrap( ) [ ..] ) . unwrap( ) ,
4238
+ channel_features: ChannelFeatures :: empty( ) , node_features: NodeFeatures :: empty( ) ,
4239
+ 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
4240
+ } ,
4241
+ ] ] ,
4242
+ } ;
4243
+
4244
+ assert_eq ! ( route. get_total_fees( ) , 250 ) ;
4245
+ assert_eq ! ( route. get_total_amount( ) , 225 ) ;
4246
+ }
4247
+
4248
+ #[ test]
4249
+ fn total_fees_multi_path ( ) {
4250
+ let route = Route {
4251
+ paths : vec ! [ vec![
4252
+ RouteHop {
4253
+ pubkey: PublicKey :: from_slice( & hex:: decode( "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619" ) . unwrap( ) [ ..] ) . unwrap( ) ,
4254
+ channel_features: ChannelFeatures :: empty( ) , node_features: NodeFeatures :: empty( ) ,
4255
+ 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
4256
+ } ,
4257
+ RouteHop {
4258
+ pubkey: PublicKey :: from_slice( & hex:: decode( "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c" ) . unwrap( ) [ ..] ) . unwrap( ) ,
4259
+ channel_features: ChannelFeatures :: empty( ) , node_features: NodeFeatures :: empty( ) ,
4260
+ 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
4261
+ } ,
4262
+ ] , vec![
4263
+ RouteHop {
4264
+ pubkey: PublicKey :: from_slice( & hex:: decode( "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619" ) . unwrap( ) [ ..] ) . unwrap( ) ,
4265
+ channel_features: ChannelFeatures :: empty( ) , node_features: NodeFeatures :: empty( ) ,
4266
+ 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
4267
+ } ,
4268
+ RouteHop {
4269
+ pubkey: PublicKey :: from_slice( & hex:: decode( "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c" ) . unwrap( ) [ ..] ) . unwrap( ) ,
4270
+ channel_features: ChannelFeatures :: empty( ) , node_features: NodeFeatures :: empty( ) ,
4271
+ 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
4272
+ } ,
4273
+ ] ] ,
4274
+ } ;
4275
+
4276
+ assert_eq ! ( route. get_total_fees( ) , 200 ) ;
4277
+ assert_eq ! ( route. get_total_amount( ) , 300 ) ;
4278
+ }
4279
+
4201
4280
#[ cfg( not( feature = "no-std" ) ) ]
4202
4281
pub ( super ) fn random_init_seed ( ) -> u64 {
4203
4282
// Because the default HashMap in std pulls OS randomness, we can use it as a (bad) RNG.
0 commit comments