diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 17ef933e0..41653cad1 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -261,6 +261,11 @@ type Config struct { // gossip syncers will be passive. NumActiveSyncers int + // NoTimestampQueries will prevent the GossipSyncer from querying + // timestamps of announcement messages from the peer and from replying + // to timestamp queries. + NoTimestampQueries bool + // RotateTicker is a ticker responsible for notifying the SyncManager // when it should rotate its active syncers. A single active syncer with // a chansSynced state will be exchanged for a passive syncer in order @@ -510,6 +515,7 @@ func New(cfg Config, selfKeyDesc *keychain.KeyDescriptor) *AuthenticatedGossiper RotateTicker: cfg.RotateTicker, HistoricalSyncTicker: cfg.HistoricalSyncTicker, NumActiveSyncers: cfg.NumActiveSyncers, + NoTimestampQueries: cfg.NoTimestampQueries, IgnoreHistoricalFilters: cfg.IgnoreHistoricalFilters, BestHeight: gossiper.latestHeight, PinnedSyncers: cfg.PinnedSyncers, diff --git a/discovery/sync_manager.go b/discovery/sync_manager.go index 8123c37eb..69916a073 100644 --- a/discovery/sync_manager.go +++ b/discovery/sync_manager.go @@ -73,6 +73,11 @@ type SyncManagerCfg struct { // gossip syncers will be passive. NumActiveSyncers int + // NoTimestampQueries will prevent the GossipSyncer from querying + // timestamps of announcement messages from the peer and from responding + // to timestamp queries + NoTimestampQueries bool + // RotateTicker is a ticker responsible for notifying the SyncManager // when it should rotate its active syncers. A single active syncer with // a chansSynced state will be exchanged for a passive syncer in order @@ -495,6 +500,7 @@ func (m *SyncManager) createGossipSyncer(peer lnpeer.Peer) *GossipSyncer { bestHeight: m.cfg.BestHeight, markGraphSynced: m.markGraphSynced, maxQueryChanRangeReplies: maxQueryChanRangeReplies, + noTimestampQueryOption: m.cfg.NoTimestampQueries, }) // Gossip syncers are initialized by default in a PassiveSync type diff --git a/discovery/sync_manager_test.go b/discovery/sync_manager_test.go index f6861f0c6..f71d1728e 100644 --- a/discovery/sync_manager_test.go +++ b/discovery/sync_manager_test.go @@ -277,6 +277,7 @@ func TestSyncManagerInitialHistoricalSync(t *testing.T) { assertMsgSent(t, peer, &lnwire.QueryChannelRange{ FirstBlockHeight: 0, NumBlocks: latestKnownHeight, + QueryOptions: lnwire.NewTimestampQueryOption(), }) // The graph should not be considered as synced since the initial @@ -379,6 +380,7 @@ func TestSyncManagerForceHistoricalSync(t *testing.T) { assertMsgSent(t, peer, &lnwire.QueryChannelRange{ FirstBlockHeight: 0, NumBlocks: latestKnownHeight, + QueryOptions: lnwire.NewTimestampQueryOption(), }) // If an additional peer connects, then a historical sync should not be @@ -394,6 +396,7 @@ func TestSyncManagerForceHistoricalSync(t *testing.T) { assertMsgSent(t, extraPeer, &lnwire.QueryChannelRange{ FirstBlockHeight: 0, NumBlocks: latestKnownHeight, + QueryOptions: lnwire.NewTimestampQueryOption(), }) } @@ -415,6 +418,7 @@ func TestSyncManagerGraphSyncedAfterHistoricalSyncReplacement(t *testing.T) { assertMsgSent(t, peer, &lnwire.QueryChannelRange{ FirstBlockHeight: 0, NumBlocks: latestKnownHeight, + QueryOptions: lnwire.NewTimestampQueryOption(), }) // The graph should not be considered as synced since the initial @@ -620,6 +624,7 @@ func assertTransitionToChansSynced(t *testing.T, s *GossipSyncer, peer *mockPeer query := &lnwire.QueryChannelRange{ FirstBlockHeight: 0, NumBlocks: latestKnownHeight, + QueryOptions: lnwire.NewTimestampQueryOption(), } assertMsgSent(t, peer, query) diff --git a/discovery/syncer.go b/discovery/syncer.go index 3f03bcea8..5940b23d4 100644 --- a/discovery/syncer.go +++ b/discovery/syncer.go @@ -271,6 +271,11 @@ type gossipSyncerCfg struct { // peer. noReplyQueries bool + // noTimestampQueryOption will prevent the GossipSyncer from querying + // timestamps of announcement messages from the peer, and it will + // prevent it from responding to timestamp queries. + noTimestampQueryOption bool + // ignoreHistoricalFilters will prevent syncers from replying with // historical data when the remote peer sets a gossip_timestamp_range. // This prevents ranges with old start times from causing us to dump the @@ -922,7 +927,7 @@ func (g *GossipSyncer) genChanRangeQuery( case newestChan.BlockHeight <= chanRangeQueryBuffer: startHeight = 0 default: - startHeight = uint32(newestChan.BlockHeight - chanRangeQueryBuffer) + startHeight = newestChan.BlockHeight - chanRangeQueryBuffer } // Determine the number of blocks to request based on our best height. @@ -945,6 +950,11 @@ func (g *GossipSyncer) genChanRangeQuery( FirstBlockHeight: startHeight, NumBlocks: numBlocks, } + + if !g.cfg.noTimestampQueryOption { + query.QueryOptions = lnwire.NewTimestampQueryOption() + } + g.curQueryRangeMsg = query return query, nil diff --git a/discovery/syncer_test.go b/discovery/syncer_test.go index 32b7b7032..9f9adcf4f 100644 --- a/discovery/syncer_test.go +++ b/discovery/syncer_test.go @@ -160,23 +160,30 @@ func newTestSyncer(hID lnwire.ShortChannelID, flags ...bool) (chan []lnwire.Message, *GossipSyncer, *mockChannelGraphTimeSeries) { - syncChannels := true - replyQueries := true + var ( + syncChannels = true + replyQueries = true + timestamps = false + ) if len(flags) > 0 { syncChannels = flags[0] } if len(flags) > 1 { replyQueries = flags[1] } + if len(flags) > 2 { + timestamps = flags[2] + } msgChan := make(chan []lnwire.Message, 20) cfg := gossipSyncerCfg{ - channelSeries: newMockChannelGraphTimeSeries(hID), - encodingType: encodingType, - chunkSize: chunkSize, - batchSize: chunkSize, - noSyncChannels: !syncChannels, - noReplyQueries: !replyQueries, + channelSeries: newMockChannelGraphTimeSeries(hID), + encodingType: encodingType, + chunkSize: chunkSize, + batchSize: chunkSize, + noSyncChannels: !syncChannels, + noReplyQueries: !replyQueries, + noTimestampQueryOption: !timestamps, sendToPeer: func(msgs ...lnwire.Message) error { msgChan <- msgs return nil @@ -2250,7 +2257,7 @@ func TestGossipSyncerHistoricalSync(t *testing.T) { // historical sync requests in this state. msgChan, syncer, _ := newTestSyncer( lnwire.ShortChannelID{BlockHeight: latestKnownHeight}, - defaultEncoding, defaultChunkSize, + defaultEncoding, defaultChunkSize, true, true, true, ) syncer.setSyncType(PassiveSync) syncer.setSyncState(chansSynced) @@ -2265,6 +2272,7 @@ func TestGossipSyncerHistoricalSync(t *testing.T) { expectedMsg := &lnwire.QueryChannelRange{ FirstBlockHeight: 0, NumBlocks: latestKnownHeight, + QueryOptions: lnwire.NewTimestampQueryOption(), } select { diff --git a/lncfg/protocol.go b/lncfg/protocol.go index 4376a145b..f8ac08e86 100644 --- a/lncfg/protocol.go +++ b/lncfg/protocol.go @@ -46,7 +46,14 @@ type ProtocolOptions struct { // NoOptionAnySegwit should be set to true if we don't want to use any // Taproot (and beyond) addresses for co-op closing. - NoOptionAnySegwit bool `long:"no-any-segwit" description:"disallow using any segiwt witness version as a co-op close address"` + NoOptionAnySegwit bool `long:"no-any-segwit" description:"disallow using any segwit witness version as a co-op close address"` + + // NoTimestampQueryOption should be set to true if we don't want our + // syncing peers to also send us the timestamps of announcement messages + // when we send them a channel range query. Setting this to true will + // also mean that we won't respond with timestamps if requested by our + // peers. + NoTimestampQueryOption bool `long:"no-timestamp-query-option" description:"do not query syncing peers for announcement timestamps and do not respond with timestamps if requested"` } // Wumbo returns true if lnd should permit the creation and acceptance of wumbo @@ -82,3 +89,11 @@ func (l *ProtocolOptions) ZeroConf() bool { func (l *ProtocolOptions) NoAnySegwit() bool { return l.NoOptionAnySegwit } + +// NoTimestampsQuery returns true if we should not ask our syncing peers to also +// send us the timestamps of announcement messages when we send them a channel +// range query, and it also means that we will not respond with timestamps if +// requested by our peer. +func (l *ProtocolOptions) NoTimestampsQuery() bool { + return l.NoTimestampQueryOption +} diff --git a/lncfg/protocol_integration.go b/lncfg/protocol_integration.go index 18e09ca72..ff74ba9e9 100644 --- a/lncfg/protocol_integration.go +++ b/lncfg/protocol_integration.go @@ -50,6 +50,13 @@ type ProtocolOptions struct { // NoOptionAnySegwit should be set to true if we don't want to use any // Taproot (and beyond) addresses for co-op closing. NoOptionAnySegwit bool `long:"no-any-segwit" description:"disallow using any segiwt witness version as a co-op close address"` + + // NoTimestampQueryOption should be set to true if we don't want our + // syncing peers to also send us the timestamps of announcement messages + // when we send them a channel range query. Setting this to true will + // also mean that we won't respond with timestamps if requested by our + // peers. + NoTimestampQueryOption bool `long:"no-timestamp-query-option" description:"do not query syncing peers for announcement timestamps and do not respond with timestamps if requested"` } // Wumbo returns true if lnd should permit the creation and acceptance of wumbo diff --git a/sample-lnd.conf b/sample-lnd.conf index f13098723..2e7f79376 100644 --- a/sample-lnd.conf +++ b/sample-lnd.conf @@ -1272,6 +1272,9 @@ ; closing. ; protocol.no-any-segwit=false +; Set to disable querying our peers for the timestamps of announcement +; messages and to disable responding to such queries +; protocol.no-timestamp-query-option=false ; Set to enable support for the experimental taproot channel type. ; protocol.simple-taproot-chans=false diff --git a/server.go b/server.go index fd53ee5e6..184e9aa90 100644 --- a/server.go +++ b/server.go @@ -1018,6 +1018,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, RotateTicker: ticker.New(discovery.DefaultSyncerRotationInterval), HistoricalSyncTicker: ticker.New(cfg.HistoricalSyncInterval), NumActiveSyncers: cfg.NumGraphSyncPeers, + NoTimestampQueries: cfg.ProtocolOptions.NoTimestampQueryOption, //nolint:lll MinimumBatchSize: 10, SubBatchDelay: cfg.Gossip.SubBatchDelay, IgnoreHistoricalFilters: cfg.IgnoreHistoricalGossipFilters,