@@ -13,6 +13,7 @@ use chain::chaininterface::{ChainError, ChainWatchInterface};
1313use ln:: features:: { ChannelFeatures , NodeFeatures } ;
1414use ln:: msgs:: { DecodeError , ErrorAction , LightningError , RoutingMessageHandler , NetAddress } ;
1515use ln:: msgs;
16+ use routing:: router:: RouteHop ;
1617use util:: ser:: { Writeable , Readable , Writer } ;
1718use util:: logger:: Logger ;
1819
@@ -202,6 +203,36 @@ impl<C: Deref + Sync + Send, L: Deref + Sync + Send> RoutingMessageHandler for N
202203 }
203204}
204205
206+ #[ derive( PartialEq , Debug ) ]
207+ /// Tracks the score of a payment by holding onto certain metadata about
208+ /// the channel. Right now it stores a count of PaymentSent and PaymentFailed
209+ /// occurances for a given channel, but there's a lot more that could be
210+ /// added down the road (eg uptime, fee rates, variation, floppiness...)
211+ pub struct ChannelScore {
212+ /// Count of occurances of PaymentSent events
213+ pub payment_sent_score : u64 ,
214+ /// Count of occurances of PaymentFailed events
215+ pub payment_failed_score : u64 ,
216+ }
217+
218+ impl Readable for ChannelScore {
219+ fn read < R : :: std:: io:: Read > ( reader : & mut R ) -> Result < ChannelScore , DecodeError > {
220+ let payment_sent_score: u64 = Readable :: read ( reader) ?;
221+ let payment_failed_score: u64 = Readable :: read ( reader) ?;
222+ Ok ( ChannelScore {
223+ payment_sent_score,
224+ payment_failed_score,
225+ } )
226+ }
227+ }
228+
229+ impl Writeable for ChannelScore {
230+ fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , :: std:: io:: Error > {
231+ self . payment_sent_score . write ( writer) ?;
232+ self . payment_failed_score . write ( writer) ?;
233+ Ok ( ( ) )
234+ }
235+ }
205236#[ derive( PartialEq , Debug ) ]
206237/// Details about one direction of a channel. Received
207238/// within a channel update.
@@ -222,6 +253,8 @@ pub struct DirectionalChannelInfo {
222253 /// Everything else is useful only for sending out for initial routing sync.
223254 /// Not stored if contains excess data to prevent DoS.
224255 pub last_update_message : Option < msgs:: ChannelUpdate > ,
256+ /// A structure that tracks the reliablity of a channel.
257+ pub channel_score : ChannelScore ,
225258}
226259
227260impl std:: fmt:: Display for DirectionalChannelInfo {
@@ -237,7 +270,8 @@ impl_writeable!(DirectionalChannelInfo, 0, {
237270 cltv_expiry_delta,
238271 htlc_minimum_msat,
239272 fees,
240- last_update_message
273+ last_update_message,
274+ channel_score
241275} ) ;
242276
243277#[ derive( PartialEq ) ]
@@ -506,6 +540,56 @@ impl NetworkGraph {
506540 None
507541 }
508542
543+ /// Increments payment_sent_score for appropriate DirectionalChannelInfos on the network graph.
544+ /// The appropriate directional channel is indentified by the RouteHop, which includes a
545+ /// PublicKey field. This is matched against the two PublicKey fields in ChannelInfo and is
546+ /// used to increment the score.
547+ pub fn score_payment_sent_for_route ( & mut self , route : Vec < Vec < RouteHop > > ) -> Result < bool , LightningError > {
548+ for path in route {
549+ for route_hop in path {
550+ let short_channel_id = route_hop. short_channel_id ;
551+ let channel = self . channels . get_mut ( & short_channel_id) . unwrap ( ) ;
552+ let directional_channel_info = if route_hop. pubkey == channel. node_one {
553+ channel. one_to_two . as_mut ( ) . unwrap ( )
554+ } else {
555+ channel. two_to_one . as_mut ( ) . unwrap ( )
556+ } ;
557+ let channel_score = & mut directional_channel_info. channel_score ;
558+ channel_score. payment_sent_score += 1 ;
559+ }
560+ }
561+ Ok ( true )
562+ }
563+
564+ /// Increments payment_failed_score for approriate DirectionalChannelInfos on the network
565+ /// graph. Like the case for scoring PaymentSent events, this method uses the node's PublicKey
566+ /// to identify the appropriate DirectionalChannelInfo to score. From there, there is a check
567+ /// against a list of at fault nodes that determines whether the node's channel score should be
568+ /// penalized for failing to execute or rewarded for executing properly.
569+ pub fn score_payment_failed_for_route ( & mut self , route : Vec < Vec < RouteHop > > , faultive_nodes : Vec < PublicKey > ) -> Result < bool , LightningError > {
570+ if faultive_nodes. len ( ) == 0 {
571+ return self . score_payment_sent_for_route ( route)
572+ }
573+ for path in route {
574+ for route_hop in path {
575+ let short_channel_id = route_hop. short_channel_id ;
576+ let channel = self . channels . get_mut ( & short_channel_id) . unwrap ( ) ;
577+ let directional_channel_info = if route_hop. pubkey == channel. node_one {
578+ channel. one_to_two . as_mut ( ) . unwrap ( )
579+ } else {
580+ channel. two_to_one . as_mut ( ) . unwrap ( )
581+ } ;
582+ let channel_score = & mut directional_channel_info. channel_score ;
583+ if faultive_nodes. contains ( & ( route_hop. pubkey ) ) {
584+ channel_score. payment_failed_score += 1 ;
585+ } else {
586+ channel_score. payment_sent_score += 1 ;
587+ }
588+ }
589+ }
590+ Ok ( true )
591+ }
592+
509593 /// For an already known node (from channel announcements), update its stored properties from a given node announcement
510594 /// Announcement signatures are checked here only if Secp256k1 object is provided.
511595 fn update_node_from_announcement ( & mut self , msg : & msgs:: NodeAnnouncement , secp_ctx : Option < & Secp256k1 < secp256k1:: VerifyOnly > > ) -> Result < bool , LightningError > {
@@ -677,7 +761,11 @@ impl NetworkGraph {
677761 base_msat: msg. contents. fee_base_msat,
678762 proportional_millionths: msg. contents. fee_proportional_millionths,
679763 } ,
680- last_update_message
764+ last_update_message,
765+ channel_score: ChannelScore {
766+ payment_sent_score: 0 ,
767+ payment_failed_score: 0 ,
768+ }
681769 } ;
682770 $target = Some ( updated_channel_dir_info) ;
683771 }
@@ -765,12 +853,13 @@ impl NetworkGraph {
765853mod tests {
766854 use chain:: chaininterface;
767855 use ln:: features:: { ChannelFeatures , NodeFeatures } ;
768- use routing:: network_graph:: { NetGraphMsgHandler , NetworkGraph } ;
856+ use routing:: network_graph:: { NetGraphMsgHandler , NetworkGraph , DirectionalChannelInfo , ChannelScore , RoutingFees } ;
769857 use ln:: msgs:: { RoutingMessageHandler , UnsignedNodeAnnouncement , NodeAnnouncement ,
770858 UnsignedChannelAnnouncement , ChannelAnnouncement , UnsignedChannelUpdate , ChannelUpdate , HTLCFailChannelUpdate } ;
771859 use util:: test_utils;
772860 use util:: logger:: Logger ;
773861 use util:: ser:: { Readable , Writeable } ;
862+ use routing:: router:: RouteHop ;
774863
775864 use bitcoin:: hashes:: sha256d:: Hash as Sha256dHash ;
776865 use bitcoin:: hashes:: Hash ;
@@ -1658,4 +1747,132 @@ mod tests {
16581747 network. write ( & mut w) . unwrap ( ) ;
16591748 assert ! ( <NetworkGraph >:: read( & mut :: std:: io:: Cursor :: new( & w. 0 ) ) . unwrap( ) == * network) ;
16601749 }
1750+
1751+ #[ test]
1752+ fn network_graph_score_payment ( ) {
1753+ // Set up a network that consists of just a channel between node_1 and node_2
1754+ let ( secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler ( ) ;
1755+ let node_1_privkey = & SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ;
1756+ let node_2_privkey = & SecretKey :: from_slice ( & [ 41 ; 32 ] ) . unwrap ( ) ;
1757+ let node_id_1 = PublicKey :: from_secret_key ( & secp_ctx, node_1_privkey) ;
1758+ let node_id_2 = PublicKey :: from_secret_key ( & secp_ctx, node_2_privkey) ;
1759+ let node_1_btckey = & SecretKey :: from_slice ( & [ 40 ; 32 ] ) . unwrap ( ) ;
1760+ let node_2_btckey = & SecretKey :: from_slice ( & [ 39 ; 32 ] ) . unwrap ( ) ;
1761+
1762+ let short_channel_id = 0 ;
1763+ let chain_hash = genesis_block ( Network :: Testnet ) . header . bitcoin_hash ( ) ;
1764+
1765+ {
1766+ // There is no nodes in the table at the beginning.
1767+ let network = net_graph_msg_handler. network_graph . read ( ) . unwrap ( ) ;
1768+ assert_eq ! ( network. get_nodes( ) . len( ) , 0 ) ;
1769+ }
1770+
1771+ {
1772+ // Announce a channel we will update
1773+ let unsigned_announcement = UnsignedChannelAnnouncement {
1774+ features : ChannelFeatures :: empty ( ) ,
1775+ chain_hash,
1776+ short_channel_id,
1777+ node_id_1,
1778+ node_id_2,
1779+ bitcoin_key_1 : PublicKey :: from_secret_key ( & secp_ctx, node_1_btckey) ,
1780+ bitcoin_key_2 : PublicKey :: from_secret_key ( & secp_ctx, node_2_btckey) ,
1781+ excess_data : Vec :: new ( ) ,
1782+ } ;
1783+
1784+ let msghash = hash_to_message ! ( & Sha256dHash :: hash( & unsigned_announcement. encode( ) [ ..] ) [ ..] ) ;
1785+ let valid_channel_announcement = ChannelAnnouncement {
1786+ node_signature_1 : secp_ctx. sign ( & msghash, node_1_privkey) ,
1787+ node_signature_2 : secp_ctx. sign ( & msghash, node_2_privkey) ,
1788+ bitcoin_signature_1 : secp_ctx. sign ( & msghash, node_1_btckey) ,
1789+ bitcoin_signature_2 : secp_ctx. sign ( & msghash, node_2_btckey) ,
1790+ contents : unsigned_announcement. clone ( ) ,
1791+ } ;
1792+ match net_graph_msg_handler. handle_channel_announcement ( & valid_channel_announcement) {
1793+ Ok ( _) => ( ) ,
1794+ Err ( _) => panic ! ( )
1795+ } ;
1796+ }
1797+
1798+ {
1799+ // At the start, the node_1 <-> node_2 channel's DirectionalChannelInfos should be 0.
1800+ let mut network = net_graph_msg_handler. network_graph . write ( ) . unwrap ( ) ;
1801+ let chan_id = network. get_nodes ( ) . get ( & node_id_1) . unwrap ( ) . channels [ 0 ] ;
1802+ let channel_info = network. channels . get_mut ( & chan_id) . unwrap ( ) ;
1803+ // Assign a DirectionalChannelInfo and ChannelScore object to one_to_two of
1804+ // channel_info
1805+ let chan_score = ChannelScore {
1806+ payment_sent_score : 0 ,
1807+ payment_failed_score : 0 ,
1808+ } ;
1809+ let dummy_routing_fee = RoutingFees {
1810+ base_msat : 0 ,
1811+ proportional_millionths : 0 ,
1812+ } ;
1813+ let dir_chan_info = DirectionalChannelInfo {
1814+ last_update : 0 ,
1815+ enabled : true ,
1816+ cltv_expiry_delta : 0 ,
1817+ htlc_minimum_msat : 0 ,
1818+ fees : dummy_routing_fee,
1819+ last_update_message : None ,
1820+ channel_score : chan_score,
1821+ } ;
1822+ channel_info. one_to_two = Some ( dir_chan_info) ;
1823+ let dir_one_to_two = channel_info. one_to_two . as_mut ( ) . unwrap ( ) ;
1824+ assert_eq ! ( dir_one_to_two. channel_score. payment_sent_score, 0 ) ;
1825+ assert_eq ! ( dir_one_to_two. channel_score. payment_failed_score, 0 ) ;
1826+ }
1827+
1828+ {
1829+ // Assume a payment is made, and node 1 is learning of a PaymentSent event. It now calls
1830+ // its score_payment_sent_for_route on itself.
1831+ let route_hop = RouteHop {
1832+ pubkey : node_id_1,
1833+ node_features : NodeFeatures :: empty ( ) ,
1834+ short_channel_id : 0 ,
1835+ channel_features : ChannelFeatures :: empty ( ) ,
1836+ fee_msat : 0 ,
1837+ cltv_expiry_delta : 0 ,
1838+ } ;
1839+ let sent_paths: Vec < RouteHop > = vec ! [ route_hop] ;
1840+ let sent_route: Vec < Vec < RouteHop > > = vec ! [ sent_paths] ;
1841+ let mut network = net_graph_msg_handler. network_graph . write ( ) . unwrap ( ) ;
1842+ let sent_res = network. score_payment_sent_for_route ( sent_route) ;
1843+ assert ! ( sent_res. unwrap( ) == true ) ;
1844+ // Check that score_payment_sent_for_route incremented the appropriate ChannelScore
1845+ let chan_id = network. get_nodes ( ) . get ( & node_id_1) . unwrap ( ) . channels [ 0 ] ;
1846+ let channel_info = network. channels . get_mut ( & chan_id) . unwrap ( ) ;
1847+ let dir_one_to_two = & channel_info. one_to_two . as_ref ( ) ;
1848+ assert_eq ! ( dir_one_to_two. unwrap( ) . channel_score. payment_sent_score, 1 ) ;
1849+ assert_eq ! ( dir_one_to_two. unwrap( ) . channel_score. payment_failed_score, 0 ) ;
1850+ }
1851+
1852+ {
1853+ let route_hop = RouteHop {
1854+ pubkey : node_id_1,
1855+ node_features : NodeFeatures :: empty ( ) ,
1856+ short_channel_id : 0 ,
1857+ channel_features : ChannelFeatures :: empty ( ) ,
1858+ fee_msat : 0 ,
1859+ cltv_expiry_delta : 0 ,
1860+ } ;
1861+ // Assume a payment fails due to node_1 (identified by its PublicKey), verify that its
1862+ // directional channel's score (node_1 -> node_2) has its PaymentFailed score
1863+ // incremented.
1864+ let faultive_nodes: Vec < PublicKey > = vec ! [ node_id_1] ;
1865+ let attempted_path: Vec < RouteHop > = vec ! [ route_hop] ;
1866+ let failed_route: Vec < Vec < RouteHop > > = vec ! [ attempted_path] ;
1867+ let mut network = net_graph_msg_handler. network_graph . write ( ) . unwrap ( ) ;
1868+ let failed_res = network. score_payment_failed_for_route ( failed_route, faultive_nodes) ;
1869+ assert ! ( failed_res. unwrap( ) == true ) ;
1870+ let chan_id = network. get_nodes ( ) . get ( & node_id_1) . unwrap ( ) . channels [ 0 ] ;
1871+ let channel_info = network. channels . get_mut ( & chan_id) . unwrap ( ) ;
1872+ assert ! ( channel_info. node_two == node_id_2) ;
1873+ let dir_one_to_two = & channel_info. one_to_two . as_ref ( ) ;
1874+ assert_eq ! ( dir_one_to_two. unwrap( ) . channel_score. payment_sent_score, 1 ) ;
1875+ assert_eq ! ( dir_one_to_two. unwrap( ) . channel_score. payment_failed_score, 1 ) ;
1876+ }
1877+ }
16611878}
0 commit comments