@@ -401,82 +401,91 @@ where C::Target: chain::Access, L::Target: Logger
401401 return ( ) ;
402402 }
403403
404- // Send a gossip_timestamp_filter to enable gossip message receipt. Note that we have to
405- // use a "all timestamps" filter as sending the current timestamp would result in missing
406- // gossip messages that are simply sent late. We could calculate the intended filter time
407- // by looking at the current time and subtracting two weeks (before which we'll reject
408- // messages), but there's not a lot of reason to bother - our peers should be discarding
409- // the same messages.
404+ // The lightning network's gossip sync system is completely broken in numerous ways.
405+ //
406+ // Given no broadly-available set-reconciliation protocol, the only reasonable approach is
407+ // to do a full sync from the first few peers we connect to, and then receive gossip
408+ // updates from all our peers normally.
409+ //
410+ // Originally, we could simply tell a peer to dump us the entire gossip table on startup,
411+ // wasting lots of bandwidth but ensuring we have the full network graph. After the initial
412+ // dump peers would always send gossip and we'd stay up-to-date with whatever our peer has
413+ // seen.
414+ //
415+ // In order to reduce the bandwidth waste, "gossip queries" were introduced, allowing you
416+ // to ask for the SCIDs of all channels in your peer's routing graph, and then only request
417+ // channel data which you are missing. Except there was no way at all to identify which
418+ // `channel_update`s you were missing, so you still had to request everything, just in a
419+ // very complicated way with some queries instead of just getting the dump.
420+ //
421+ // Later, an option was added to fetch the latest timestamps of the `channel_update`s to
422+ // make efficient sync possible, however it has yet to be implemented in lnd, which makes
423+ // relying on it useless.
424+ //
425+ // After gossip queries were introduced, support for receiving a full gossip table dump on
426+ // connection was removed from several nodes, making it impossible to get a full sync
427+ // without using the "gossip queries" messages.
428+ //
429+ // Once you opt into "gossip queries" the only way to receive any gossip updates that a
430+ // peer receives after you connect, you must send a `gossip_timestamp_filter` message. This
431+ // message, as the name implies, tells the peer to not forward any gossip messages with a
432+ // timestamp older than a given value (not the time the peer received the filter, but the
433+ // timestamp in the update message, which is often hours behind when the peer received the
434+ // message).
435+ //
436+ // Obnoxiously, `gossip_timestamp_filter` isn't *just* a filter, but its also a request for
437+ // your peer to send you the full routing graph. Thus, in order to tell a peer to send you
438+ // any updates as it sees them, you have to also ask for the full routing graph to be
439+ // synced. If you set a timestamp filter near the current time, peers will simply not
440+ // forward any new updates they see to you which were generated some time ago (which is
441+ // not uncommon). If you instead set a timestamp filter near 0 (or two weeks ago), you will
442+ // always get the full routing graph from all your peers.
443+ //
444+ // Most lightning nodes today opt to simply turn off receiving gossip data which only
445+ // propagated some time after it was generated, and, worse, often disable gossiping with
446+ // several peers after their first connection. The second behavior can cause gossip to not
447+ // propagate fully if there are cuts in the gossiping subgraph.
448+ //
449+ // In an attempt to cut a middle ground between always fetching the full graph from all of
450+ // our peers and never receiving gossip from peers at all, we send all of our peers a
451+ // `gossip_timestamp_filter`, with the filter time set either two weeks ago or an hour ago.
452+ //
453+ // For no-std builds, we bury our head in the sand and do a full sync on each connection.
454+ let should_request_full_sync = self . should_request_full_sync ( & their_node_id) ;
455+ #[ allow( unused_mut, unused_assignments) ]
456+ let mut gossip_start_time = 0 ;
457+ #[ cfg( feature = "std" ) ]
458+ {
459+ gossip_start_time = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . expect ( "Time must be > 1970" ) . as_secs ( ) ;
460+ if should_request_full_sync {
461+ gossip_start_time -= 60 * 60 * 24 * 7 * 2 ; // 2 weeks ago
462+ } else {
463+ gossip_start_time -= 60 * 60 ; // an hour ago
464+ }
465+ }
466+
410467 let mut pending_events = self . pending_events . lock ( ) . unwrap ( ) ;
411468 pending_events. push ( MessageSendEvent :: SendGossipTimestampFilter {
412469 node_id : their_node_id. clone ( ) ,
413470 msg : GossipTimestampFilter {
414471 chain_hash : self . network_graph . genesis_hash ,
415- first_timestamp : 0 ,
472+ first_timestamp : gossip_start_time as u32 , // 2106 issue!
416473 timestamp_range : u32:: max_value ( ) ,
417474 } ,
418475 } ) ;
419-
420- // Check if we need to perform a full synchronization with this peer
421- if !self . should_request_full_sync ( & their_node_id) {
422- return ( ) ;
423- }
424-
425- let first_blocknum = 0 ;
426- let number_of_blocks = 0xffffffff ;
427- log_debug ! ( self . logger, "Sending query_channel_range peer={}, first_blocknum={}, number_of_blocks={}" , log_pubkey!( their_node_id) , first_blocknum, number_of_blocks) ;
428- pending_events. push ( MessageSendEvent :: SendChannelRangeQuery {
429- node_id : their_node_id. clone ( ) ,
430- msg : QueryChannelRange {
431- chain_hash : self . network_graph . genesis_hash ,
432- first_blocknum,
433- number_of_blocks,
434- } ,
435- } ) ;
436476 }
437477
438- /// Statelessly processes a reply to a channel range query by immediately
439- /// sending an SCID query with SCIDs in the reply. To keep this handler
440- /// stateless, it does not validate the sequencing of replies for multi-
441- /// reply ranges. It does not validate whether the reply(ies) cover the
442- /// queried range. It also does not filter SCIDs to only those in the
443- /// original query range. We also do not validate that the chain_hash
444- /// matches the chain_hash of the NetworkGraph. Any chan_ann message that
445- /// does not match our chain_hash will be rejected when the announcement is
446- /// processed.
447- fn handle_reply_channel_range ( & self , their_node_id : & PublicKey , msg : ReplyChannelRange ) -> Result < ( ) , LightningError > {
448- log_debug ! ( self . logger, "Handling reply_channel_range peer={}, first_blocknum={}, number_of_blocks={}, sync_complete={}, scids={}" , log_pubkey!( their_node_id) , msg. first_blocknum, msg. number_of_blocks, msg. sync_complete, msg. short_channel_ids. len( ) , ) ;
449-
450- log_debug ! ( self . logger, "Sending query_short_channel_ids peer={}, batch_size={}" , log_pubkey!( their_node_id) , msg. short_channel_ids. len( ) ) ;
451- let mut pending_events = self . pending_events . lock ( ) . unwrap ( ) ;
452- pending_events. push ( MessageSendEvent :: SendShortIdsQuery {
453- node_id : their_node_id. clone ( ) ,
454- msg : QueryShortChannelIds {
455- chain_hash : msg. chain_hash ,
456- short_channel_ids : msg. short_channel_ids ,
457- }
458- } ) ;
459-
478+ fn handle_reply_channel_range ( & self , _their_node_id : & PublicKey , _msg : ReplyChannelRange ) -> Result < ( ) , LightningError > {
479+ // We don't make queries, so should never receive replies. If, in the future, the set
480+ // reconciliation extensions to gossip queries become broadly supported, we should revert
481+ // this code to its state pre-0.0.106.
460482 Ok ( ( ) )
461483 }
462484
463- /// When an SCID query is initiated the remote peer will begin streaming
464- /// gossip messages. In the event of a failure, we may have received
465- /// some channel information. Before trying with another peer, the
466- /// caller should update its set of SCIDs that need to be queried.
467- fn handle_reply_short_channel_ids_end ( & self , their_node_id : & PublicKey , msg : ReplyShortChannelIdsEnd ) -> Result < ( ) , LightningError > {
468- log_debug ! ( self . logger, "Handling reply_short_channel_ids_end peer={}, full_information={}" , log_pubkey!( their_node_id) , msg. full_information) ;
469-
470- // If the remote node does not have up-to-date information for the
471- // chain_hash they will set full_information=false. We can fail
472- // the result and try again with a different peer.
473- if !msg. full_information {
474- return Err ( LightningError {
475- err : String :: from ( "Received reply_short_channel_ids_end with no information" ) ,
476- action : ErrorAction :: IgnoreError
477- } ) ;
478- }
479-
485+ fn handle_reply_short_channel_ids_end ( & self , _their_node_id : & PublicKey , _msg : ReplyShortChannelIdsEnd ) -> Result < ( ) , LightningError > {
486+ // We don't make queries, so should never receive replies. If, in the future, the set
487+ // reconciliation extensions to gossip queries become broadly supported, we should revert
488+ // this code to its state pre-0.0.106.
480489 Ok ( ( ) )
481490 }
482491
@@ -1535,7 +1544,7 @@ mod tests {
15351544 use routing:: network_graph:: { NetGraphMsgHandler , NetworkGraph , NetworkUpdate , MAX_EXCESS_BYTES_FOR_RELAY } ;
15361545 use ln:: msgs:: { Init , OptionalField , RoutingMessageHandler , UnsignedNodeAnnouncement , NodeAnnouncement ,
15371546 UnsignedChannelAnnouncement , ChannelAnnouncement , UnsignedChannelUpdate , ChannelUpdate ,
1538- ReplyChannelRange , ReplyShortChannelIdsEnd , QueryChannelRange , QueryShortChannelIds , MAX_VALUE_MSAT } ;
1547+ ReplyChannelRange , QueryChannelRange , QueryShortChannelIds , MAX_VALUE_MSAT } ;
15391548 use util:: test_utils;
15401549 use util:: logger:: Logger ;
15411550 use util:: ser:: { Readable , Writeable } ;
@@ -2272,15 +2281,16 @@ mod tests {
22722281 }
22732282
22742283 #[ test]
2284+ #[ cfg( feature = "std" ) ]
22752285 fn calling_sync_routing_table ( ) {
2286+ use std:: time:: { SystemTime , UNIX_EPOCH } ;
2287+
22762288 let network_graph = create_network_graph ( ) ;
22772289 let ( secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler ( & network_graph) ;
22782290 let node_privkey_1 = & SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ;
22792291 let node_id_1 = PublicKey :: from_secret_key ( & secp_ctx, node_privkey_1) ;
22802292
22812293 let chain_hash = genesis_block ( Network :: Testnet ) . header . block_hash ( ) ;
2282- let first_blocknum = 0 ;
2283- let number_of_blocks = 0xffff_ffff ;
22842294
22852295 // It should ignore if gossip_queries feature is not enabled
22862296 {
@@ -2290,132 +2300,23 @@ mod tests {
22902300 assert_eq ! ( events. len( ) , 0 ) ;
22912301 }
22922302
2293- // It should send a query_channel_message with the correct information
2303+ // It should send a gossip_timestamp_filter with the correct information
22942304 {
22952305 let init_msg = Init { features : InitFeatures :: known ( ) , remote_network_address : None } ;
22962306 net_graph_msg_handler. peer_connected ( & node_id_1, & init_msg) ;
22972307 let events = net_graph_msg_handler. get_and_clear_pending_msg_events ( ) ;
2298- assert_eq ! ( events. len( ) , 2 ) ;
2308+ assert_eq ! ( events. len( ) , 1 ) ;
22992309 match & events[ 0 ] {
23002310 MessageSendEvent :: SendGossipTimestampFilter { node_id, msg } => {
23012311 assert_eq ! ( node_id, & node_id_1) ;
23022312 assert_eq ! ( msg. chain_hash, chain_hash) ;
2303- assert_eq ! ( msg. first_timestamp, 0 ) ;
2313+ let expected_timestamp = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . expect ( "Time must be > 1970" ) . as_secs ( ) ;
2314+ assert ! ( ( msg. first_timestamp as u64 ) >= expected_timestamp - 60 * 60 * 24 * 7 * 2 ) ;
2315+ assert ! ( ( msg. first_timestamp as u64 ) < expected_timestamp - 60 * 60 * 24 * 7 * 2 + 10 ) ;
23042316 assert_eq ! ( msg. timestamp_range, u32 :: max_value( ) ) ;
23052317 } ,
23062318 _ => panic ! ( "Expected MessageSendEvent::SendChannelRangeQuery" )
23072319 } ;
2308- match & events[ 1 ] {
2309- MessageSendEvent :: SendChannelRangeQuery { node_id, msg } => {
2310- assert_eq ! ( node_id, & node_id_1) ;
2311- assert_eq ! ( msg. chain_hash, chain_hash) ;
2312- assert_eq ! ( msg. first_blocknum, first_blocknum) ;
2313- assert_eq ! ( msg. number_of_blocks, number_of_blocks) ;
2314- } ,
2315- _ => panic ! ( "Expected MessageSendEvent::SendChannelRangeQuery" )
2316- } ;
2317- }
2318-
2319- // It should not enqueue a query when should_request_full_sync return false.
2320- // The initial implementation allows syncing with the first 5 peers after
2321- // which should_request_full_sync will return false
2322- {
2323- let network_graph = create_network_graph ( ) ;
2324- let ( secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler ( & network_graph) ;
2325- let init_msg = Init { features : InitFeatures :: known ( ) , remote_network_address : None } ;
2326- for n in 1 ..7 {
2327- let node_privkey = & SecretKey :: from_slice ( & [ n; 32 ] ) . unwrap ( ) ;
2328- let node_id = PublicKey :: from_secret_key ( & secp_ctx, node_privkey) ;
2329- net_graph_msg_handler. peer_connected ( & node_id, & init_msg) ;
2330- let events = net_graph_msg_handler. get_and_clear_pending_msg_events ( ) ;
2331- if n <= 5 {
2332- assert_eq ! ( events. len( ) , 2 ) ;
2333- } else {
2334- // Even after the we stop sending the explicit query, we should still send a
2335- // gossip_timestamp_filter on each new connection.
2336- assert_eq ! ( events. len( ) , 1 ) ;
2337- }
2338-
2339- }
2340- }
2341- }
2342-
2343- #[ test]
2344- fn handling_reply_channel_range ( ) {
2345- let network_graph = create_network_graph ( ) ;
2346- let ( secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler ( & network_graph) ;
2347- let node_privkey_1 = & SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ;
2348- let node_id_1 = PublicKey :: from_secret_key ( & secp_ctx, node_privkey_1) ;
2349-
2350- let chain_hash = genesis_block ( Network :: Testnet ) . header . block_hash ( ) ;
2351-
2352- // Test receipt of a single reply that should enqueue an SCID query
2353- // matching the SCIDs in the reply
2354- {
2355- let result = net_graph_msg_handler. handle_reply_channel_range ( & node_id_1, ReplyChannelRange {
2356- chain_hash,
2357- sync_complete : true ,
2358- first_blocknum : 0 ,
2359- number_of_blocks : 2000 ,
2360- short_channel_ids : vec ! [
2361- 0x0003e0_000000_0000 , // 992x0x0
2362- 0x0003e8_000000_0000 , // 1000x0x0
2363- 0x0003e9_000000_0000 , // 1001x0x0
2364- 0x0003f0_000000_0000 , // 1008x0x0
2365- 0x00044c_000000_0000 , // 1100x0x0
2366- 0x0006e0_000000_0000 , // 1760x0x0
2367- ] ,
2368- } ) ;
2369- assert ! ( result. is_ok( ) ) ;
2370-
2371- // We expect to emit a query_short_channel_ids message with the received scids
2372- let events = net_graph_msg_handler. get_and_clear_pending_msg_events ( ) ;
2373- assert_eq ! ( events. len( ) , 1 ) ;
2374- match & events[ 0 ] {
2375- MessageSendEvent :: SendShortIdsQuery { node_id, msg } => {
2376- assert_eq ! ( node_id, & node_id_1) ;
2377- assert_eq ! ( msg. chain_hash, chain_hash) ;
2378- assert_eq ! ( msg. short_channel_ids, vec![
2379- 0x0003e0_000000_0000 , // 992x0x0
2380- 0x0003e8_000000_0000 , // 1000x0x0
2381- 0x0003e9_000000_0000 , // 1001x0x0
2382- 0x0003f0_000000_0000 , // 1008x0x0
2383- 0x00044c_000000_0000 , // 1100x0x0
2384- 0x0006e0_000000_0000 , // 1760x0x0
2385- ] ) ;
2386- } ,
2387- _ => panic ! ( "expected MessageSendEvent::SendShortIdsQuery" ) ,
2388- }
2389- }
2390- }
2391-
2392- #[ test]
2393- fn handling_reply_short_channel_ids ( ) {
2394- let network_graph = create_network_graph ( ) ;
2395- let ( secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler ( & network_graph) ;
2396- let node_privkey = & SecretKey :: from_slice ( & [ 41 ; 32 ] ) . unwrap ( ) ;
2397- let node_id = PublicKey :: from_secret_key ( & secp_ctx, node_privkey) ;
2398-
2399- let chain_hash = genesis_block ( Network :: Testnet ) . header . block_hash ( ) ;
2400-
2401- // Test receipt of a successful reply
2402- {
2403- let result = net_graph_msg_handler. handle_reply_short_channel_ids_end ( & node_id, ReplyShortChannelIdsEnd {
2404- chain_hash,
2405- full_information : true ,
2406- } ) ;
2407- assert ! ( result. is_ok( ) ) ;
2408- }
2409-
2410- // Test receipt of a reply that indicates the peer does not maintain up-to-date information
2411- // for the chain_hash requested in the query.
2412- {
2413- let result = net_graph_msg_handler. handle_reply_short_channel_ids_end ( & node_id, ReplyShortChannelIdsEnd {
2414- chain_hash,
2415- full_information : false ,
2416- } ) ;
2417- assert ! ( result. is_err( ) ) ;
2418- assert_eq ! ( result. err( ) . unwrap( ) . err, "Received reply_short_channel_ids_end with no information" ) ;
24192320 }
24202321 }
24212322
0 commit comments