@@ -43,6 +43,13 @@ use sync::Mutex;
43
43
use core:: ops:: Deref ;
44
44
use bitcoin:: hashes:: hex:: ToHex ;
45
45
46
+ #[ cfg( feature = "std" ) ]
47
+ use std:: time:: { SystemTime , UNIX_EPOCH } ;
48
+
49
+ /// We remove stale channel directional info two weeks after the last update, per BOLT 7's
50
+ /// suggestion.
51
+ const STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS : u64 = 60 * 60 * 24 * 14 ;
52
+
46
53
/// The maximum number of extra bytes which we do not understand in a gossip message before we will
47
54
/// refuse to relay the message.
48
55
const MAX_EXCESS_BYTES_FOR_RELAY : usize = 1024 ;
@@ -628,6 +635,10 @@ pub struct ChannelInfo {
628
635
/// Everything else is useful only for sending out for initial routing sync.
629
636
/// Not stored if contains excess data to prevent DoS.
630
637
pub announcement_message : Option < ChannelAnnouncement > ,
638
+ /// The timestamp when we received the announcement, if we are running with feature = "std"
639
+ /// (which we can probably assume we are - no-std environments probably won't have a full
640
+ /// network graph in memory!).
641
+ announcement_received_time : u64 ,
631
642
}
632
643
633
644
impl fmt:: Display for ChannelInfo {
@@ -640,6 +651,7 @@ impl fmt::Display for ChannelInfo {
640
651
641
652
impl_writeable_tlv_based ! ( ChannelInfo , {
642
653
( 0 , features, required) ,
654
+ ( 1 , announcement_received_time, ( default_value, 0 ) ) ,
643
655
( 2 , node_one, required) ,
644
656
( 4 , one_to_two, required) ,
645
657
( 6 , node_two, required) ,
@@ -952,6 +964,13 @@ impl NetworkGraph {
952
964
} ,
953
965
} ;
954
966
967
+ #[ allow( unused_mut, unused_assignments) ]
968
+ let mut announcement_received_time = 0 ;
969
+ #[ cfg( feature = "std" ) ]
970
+ {
971
+ announcement_received_time = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . expect ( "Time must be > 1970" ) . as_secs ( ) ;
972
+ }
973
+
955
974
let chan_info = ChannelInfo {
956
975
features : msg. features . clone ( ) ,
957
976
node_one : NodeId :: from_pubkey ( & msg. node_id_1 ) ,
@@ -961,6 +980,7 @@ impl NetworkGraph {
961
980
capacity_sats : utxo_value,
962
981
announcement_message : if msg. excess_data . len ( ) <= MAX_EXCESS_BYTES_FOR_RELAY
963
982
{ full_msg. cloned ( ) } else { None } ,
983
+ announcement_received_time,
964
984
} ;
965
985
966
986
let mut channels = self . channels . write ( ) . unwrap ( ) ;
@@ -1045,6 +1065,67 @@ impl NetworkGraph {
1045
1065
}
1046
1066
}
1047
1067
1068
+ #[ cfg( feature = "std" ) ]
1069
+ /// Removes information about channels that we haven't heard any updates about in some time.
1070
+ /// This can be used regularly to prune the network graph of channels that likely no longer
1071
+ /// exist.
1072
+ ///
1073
+ /// While there is no formal requirement that nodes regularly re-broadcast their channel
1074
+ /// updates every two weeks, the non-normative section of BOLT 7 currently suggests that
1075
+ /// pruning occur for updates which are at least two weeks old, which we implement here.
1076
+ ///
1077
+ ///
1078
+ /// This method is only available with the `std` feature. See
1079
+ /// [`NetworkGraph::remove_stale_channels_with_time`] for `no-std` use.
1080
+ pub fn remove_stale_channels ( & self ) {
1081
+ let time = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . expect ( "Time must be > 1970" ) . as_secs ( ) ;
1082
+ self . remove_stale_channels_with_time ( time) ;
1083
+ }
1084
+
1085
+ /// Removes information about channels that we haven't heard any updates about in some time.
1086
+ /// This can be used regularly to prune the network graph of channels that likely no longer
1087
+ /// exist.
1088
+ ///
1089
+ /// While there is no formal requirement that nodes regularly re-broadcast their channel
1090
+ /// updates every two weeks, the non-normative section of BOLT 7 currently suggests that
1091
+ /// pruning occur for updates which are at least two weeks old, which we implement here.
1092
+ ///
1093
+ /// This function takes the current unix time as an argument. For users with the `std` feature
1094
+ /// enabled, [`NetworkGraph::remove_stale_channels`] may be preferable.
1095
+ pub fn remove_stale_channels_with_time ( & self , current_time_unix : u64 ) {
1096
+ let mut channels = self . channels . write ( ) . unwrap ( ) ;
1097
+ // Time out if we haven't received an update in at least 14 days.
1098
+ if current_time_unix > u32:: max_value ( ) as u64 { return ; } // Remove by 2106
1099
+ if current_time_unix < STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS { return ; }
1100
+ let min_time_unix: u32 = ( current_time_unix - STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS ) as u32 ;
1101
+ // Sadly BTreeMap::retain was only stabilized in 1.53 so we can't switch to it for some
1102
+ // time.
1103
+ let mut scids_to_remove = Vec :: new ( ) ;
1104
+ for ( scid, info) in channels. iter_mut ( ) {
1105
+ if info. one_to_two . is_some ( ) && info. one_to_two . as_ref ( ) . unwrap ( ) . last_update < min_time_unix {
1106
+ info. one_to_two = None ;
1107
+ }
1108
+ if info. two_to_one . is_some ( ) && info. two_to_one . as_ref ( ) . unwrap ( ) . last_update < min_time_unix {
1109
+ info. two_to_one = None ;
1110
+ }
1111
+ if info. one_to_two . is_none ( ) && info. two_to_one . is_none ( ) {
1112
+ // We check the announcement_received_time here to ensure we don't drop
1113
+ // announcements that we just received and are just waiting for our peer to send a
1114
+ // channel_update for.
1115
+ if info. announcement_received_time < min_time_unix as u64 {
1116
+ scids_to_remove. push ( * scid) ;
1117
+ }
1118
+ }
1119
+ }
1120
+ if !scids_to_remove. is_empty ( ) {
1121
+ let mut nodes = self . nodes . write ( ) . unwrap ( ) ;
1122
+ for scid in scids_to_remove {
1123
+ let info = channels. remove ( & scid) . expect ( "We just accessed this scid, it should be present" ) ;
1124
+ Self :: remove_channel_in_nodes ( & mut nodes, & info, scid) ;
1125
+ }
1126
+ }
1127
+ }
1128
+
1048
1129
/// For an already known (from announcement) channel, update info about one of the directions
1049
1130
/// of the channel.
1050
1131
///
@@ -1250,6 +1331,8 @@ mod tests {
1250
1331
use util:: events:: { Event , EventHandler , MessageSendEvent , MessageSendEventsProvider } ;
1251
1332
use util:: scid_utils:: scid_from_parts;
1252
1333
1334
+ use super :: STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS ;
1335
+
1253
1336
use bitcoin:: hashes:: sha256d:: Hash as Sha256dHash ;
1254
1337
use bitcoin:: hashes:: Hash ;
1255
1338
use bitcoin:: network:: constants:: Network ;
@@ -1733,28 +1816,73 @@ mod tests {
1733
1816
}
1734
1817
1735
1818
// Permanent closing deletes a channel
1819
+ net_graph_msg_handler. handle_event ( & Event :: PaymentPathFailed {
1820
+ payment_id : None ,
1821
+ payment_hash : PaymentHash ( [ 0 ; 32 ] ) ,
1822
+ rejected_by_dest : false ,
1823
+ all_paths_failed : true ,
1824
+ path : vec ! [ ] ,
1825
+ network_update : Some ( NetworkUpdate :: ChannelClosed {
1826
+ short_channel_id,
1827
+ is_permanent : true ,
1828
+ } ) ,
1829
+ short_channel_id : None ,
1830
+ retry : None ,
1831
+ error_code : None ,
1832
+ error_data : None ,
1833
+ } ) ;
1834
+
1835
+ assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 0 ) ;
1836
+ // Nodes are also deleted because there are no associated channels anymore
1837
+ assert_eq ! ( network_graph. read_only( ) . nodes( ) . len( ) , 0 ) ;
1838
+ // TODO: Test NetworkUpdate::NodeFailure, which is not implemented yet.
1839
+ }
1840
+
1841
+ #[ test]
1842
+ fn test_channel_timeouts ( ) {
1843
+ // Test the removal of channels with `remove_stale_channels`.
1844
+ let logger = test_utils:: TestLogger :: new ( ) ;
1845
+ let chain_source = Arc :: new ( test_utils:: TestChainSource :: new ( Network :: Testnet ) ) ;
1846
+ let genesis_hash = genesis_block ( Network :: Testnet ) . header . block_hash ( ) ;
1847
+ let network_graph = NetworkGraph :: new ( genesis_hash) ;
1848
+ let net_graph_msg_handler = NetGraphMsgHandler :: new ( & network_graph, Some ( chain_source. clone ( ) ) , & logger) ;
1849
+ let secp_ctx = Secp256k1 :: new ( ) ;
1850
+
1851
+ let node_1_privkey = & SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ;
1852
+ let node_2_privkey = & SecretKey :: from_slice ( & [ 41 ; 32 ] ) . unwrap ( ) ;
1853
+
1854
+ let valid_channel_announcement = get_signed_channel_announcement ( |_| { } , node_1_privkey, node_2_privkey, & secp_ctx) ;
1855
+ let short_channel_id = valid_channel_announcement. contents . short_channel_id ;
1856
+ let chain_source: Option < & test_utils:: TestChainSource > = None ;
1857
+ assert ! ( network_graph. update_channel_from_announcement( & valid_channel_announcement, & chain_source, & secp_ctx) . is_ok( ) ) ;
1858
+ assert ! ( network_graph. read_only( ) . channels( ) . get( & short_channel_id) . is_some( ) ) ;
1859
+
1860
+ let valid_channel_update = get_signed_channel_update ( |_| { } , node_1_privkey, & secp_ctx) ;
1861
+ assert ! ( net_graph_msg_handler. handle_channel_update( & valid_channel_update) . is_ok( ) ) ;
1862
+ assert ! ( network_graph. read_only( ) . channels( ) . get( & short_channel_id) . unwrap( ) . one_to_two. is_some( ) ) ;
1863
+
1864
+ network_graph. remove_stale_channels_with_time ( 100 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS ) ;
1865
+ assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 1 ) ;
1866
+ assert_eq ! ( network_graph. read_only( ) . nodes( ) . len( ) , 2 ) ;
1867
+
1868
+ network_graph. remove_stale_channels_with_time ( 101 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS ) ;
1869
+ #[ cfg( feature = "std" ) ]
1736
1870
{
1737
- net_graph_msg_handler. handle_event ( & Event :: PaymentPathFailed {
1738
- payment_id : None ,
1739
- payment_hash : PaymentHash ( [ 0 ; 32 ] ) ,
1740
- rejected_by_dest : false ,
1741
- all_paths_failed : true ,
1742
- path : vec ! [ ] ,
1743
- network_update : Some ( NetworkUpdate :: ChannelClosed {
1744
- short_channel_id,
1745
- is_permanent : true ,
1746
- } ) ,
1747
- short_channel_id : None ,
1748
- retry : None ,
1749
- error_code : None ,
1750
- error_data : None ,
1751
- } ) ;
1871
+ // In std mode, a further check is performed before fully removing the channel -
1872
+ // the channel_announcement must have been received at least two weeks ago. We
1873
+ // fudge that here by indicating the time has jumped two weeks. Note that the
1874
+ // directional channel information will have been removed already..
1875
+ assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 1 ) ;
1876
+ assert_eq ! ( network_graph. read_only( ) . nodes( ) . len( ) , 2 ) ;
1877
+ assert ! ( network_graph. read_only( ) . channels( ) . get( & short_channel_id) . unwrap( ) . one_to_two. is_none( ) ) ;
1752
1878
1753
- assert_eq ! ( network_graph . read_only ( ) . channels ( ) . len ( ) , 0 ) ;
1754
- // Nodes are also deleted because there are no associated channels anymore
1755
- assert_eq ! ( network_graph. read_only ( ) . nodes ( ) . len ( ) , 0 ) ;
1879
+ use std :: time :: { SystemTime , UNIX_EPOCH } ;
1880
+ let announcement_time = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . expect ( "Time must be > 1970" ) . as_secs ( ) ;
1881
+ network_graph. remove_stale_channels_with_time ( announcement_time + 1 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS ) ;
1756
1882
}
1757
- // TODO: Test NetworkUpdate::NodeFailure, which is not implemented yet.
1883
+
1884
+ assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 0 ) ;
1885
+ assert_eq ! ( network_graph. read_only( ) . nodes( ) . len( ) , 0 ) ;
1758
1886
}
1759
1887
1760
1888
#[ test]
0 commit comments