discovery: limit NumBlocks to best known height for outgoing QueryChannelRange
This is done to ensure we don't receive replies for channels in blocks not currently known to us, which we wouldn't be able to process.
This commit is contained in:
parent
592a0c5699
commit
c5fc7334a4
@ -343,15 +343,17 @@ func New(cfg Config, selfKey *btcec.PublicKey) *AuthenticatedGossiper {
|
|||||||
channelMtx: multimutex.NewMutex(),
|
channelMtx: multimutex.NewMutex(),
|
||||||
recentRejects: make(map[uint64]struct{}),
|
recentRejects: make(map[uint64]struct{}),
|
||||||
heightForLastChanUpdate: make(map[uint64][2]uint32),
|
heightForLastChanUpdate: make(map[uint64][2]uint32),
|
||||||
syncMgr: newSyncManager(&SyncManagerCfg{
|
}
|
||||||
|
|
||||||
|
gossiper.syncMgr = newSyncManager(&SyncManagerCfg{
|
||||||
ChainHash: cfg.ChainHash,
|
ChainHash: cfg.ChainHash,
|
||||||
ChanSeries: cfg.ChanSeries,
|
ChanSeries: cfg.ChanSeries,
|
||||||
RotateTicker: cfg.RotateTicker,
|
RotateTicker: cfg.RotateTicker,
|
||||||
HistoricalSyncTicker: cfg.HistoricalSyncTicker,
|
HistoricalSyncTicker: cfg.HistoricalSyncTicker,
|
||||||
NumActiveSyncers: cfg.NumActiveSyncers,
|
NumActiveSyncers: cfg.NumActiveSyncers,
|
||||||
IgnoreHistoricalFilters: cfg.IgnoreHistoricalFilters,
|
IgnoreHistoricalFilters: cfg.IgnoreHistoricalFilters,
|
||||||
}),
|
BestHeight: gossiper.latestHeight,
|
||||||
}
|
})
|
||||||
|
|
||||||
gossiper.reliableSender = newReliableSender(&reliableSenderCfg{
|
gossiper.reliableSender = newReliableSender(&reliableSenderCfg{
|
||||||
NotifyWhenOnline: cfg.NotifyWhenOnline,
|
NotifyWhenOnline: cfg.NotifyWhenOnline,
|
||||||
@ -2644,3 +2646,10 @@ func IsKeepAliveUpdate(update *lnwire.ChannelUpdate,
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// latestHeight returns the gossiper's latest height known of the chain.
|
||||||
|
func (d *AuthenticatedGossiper) latestHeight() uint32 {
|
||||||
|
d.Lock()
|
||||||
|
defer d.Unlock()
|
||||||
|
return d.bestHeight
|
||||||
|
}
|
||||||
|
@ -89,6 +89,9 @@ type SyncManagerCfg struct {
|
|||||||
// This prevents ranges with old start times from causing us to dump the
|
// This prevents ranges with old start times from causing us to dump the
|
||||||
// graph on connect.
|
// graph on connect.
|
||||||
IgnoreHistoricalFilters bool
|
IgnoreHistoricalFilters bool
|
||||||
|
|
||||||
|
// BestHeight returns the latest height known of the chain.
|
||||||
|
BestHeight func() uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncManager is a subsystem of the gossiper that manages the gossip syncers
|
// SyncManager is a subsystem of the gossiper that manages the gossip syncers
|
||||||
@ -420,6 +423,9 @@ func (m *SyncManager) createGossipSyncer(peer lnpeer.Peer) *GossipSyncer {
|
|||||||
return peer.SendMessageLazy(true, msgs...)
|
return peer.SendMessageLazy(true, msgs...)
|
||||||
},
|
},
|
||||||
ignoreHistoricalFilters: m.cfg.IgnoreHistoricalFilters,
|
ignoreHistoricalFilters: m.cfg.IgnoreHistoricalFilters,
|
||||||
|
maxUndelayedQueryReplies: DefaultMaxUndelayedQueryReplies,
|
||||||
|
delayedQueryReplyInterval: DefaultDelayedQueryReplyInterval,
|
||||||
|
bestHeight: m.cfg.BestHeight,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Gossip syncers are initialized by default in a PassiveSync type
|
// Gossip syncers are initialized by default in a PassiveSync type
|
||||||
|
@ -2,7 +2,6 @@ package discovery
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
@ -34,6 +33,9 @@ func newTestSyncManager(numActiveSyncers int) *SyncManager {
|
|||||||
RotateTicker: ticker.NewForce(DefaultSyncerRotationInterval),
|
RotateTicker: ticker.NewForce(DefaultSyncerRotationInterval),
|
||||||
HistoricalSyncTicker: ticker.NewForce(DefaultHistoricalSyncInterval),
|
HistoricalSyncTicker: ticker.NewForce(DefaultHistoricalSyncInterval),
|
||||||
NumActiveSyncers: numActiveSyncers,
|
NumActiveSyncers: numActiveSyncers,
|
||||||
|
BestHeight: func() uint32 {
|
||||||
|
return latestKnownHeight
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +204,7 @@ func TestSyncManagerInitialHistoricalSync(t *testing.T) {
|
|||||||
syncMgr.InitSyncState(peer)
|
syncMgr.InitSyncState(peer)
|
||||||
assertMsgSent(t, peer, &lnwire.QueryChannelRange{
|
assertMsgSent(t, peer, &lnwire.QueryChannelRange{
|
||||||
FirstBlockHeight: 0,
|
FirstBlockHeight: 0,
|
||||||
NumBlocks: math.MaxUint32,
|
NumBlocks: latestKnownHeight,
|
||||||
})
|
})
|
||||||
|
|
||||||
// The graph should not be considered as synced since the initial
|
// The graph should not be considered as synced since the initial
|
||||||
@ -290,7 +292,7 @@ func TestSyncManagerForceHistoricalSync(t *testing.T) {
|
|||||||
syncMgr.InitSyncState(peer)
|
syncMgr.InitSyncState(peer)
|
||||||
assertMsgSent(t, peer, &lnwire.QueryChannelRange{
|
assertMsgSent(t, peer, &lnwire.QueryChannelRange{
|
||||||
FirstBlockHeight: 0,
|
FirstBlockHeight: 0,
|
||||||
NumBlocks: math.MaxUint32,
|
NumBlocks: latestKnownHeight,
|
||||||
})
|
})
|
||||||
|
|
||||||
// If an additional peer connects, then a historical sync should not be
|
// If an additional peer connects, then a historical sync should not be
|
||||||
@ -305,7 +307,7 @@ func TestSyncManagerForceHistoricalSync(t *testing.T) {
|
|||||||
syncMgr.cfg.HistoricalSyncTicker.(*ticker.Force).Force <- time.Time{}
|
syncMgr.cfg.HistoricalSyncTicker.(*ticker.Force).Force <- time.Time{}
|
||||||
assertMsgSent(t, extraPeer, &lnwire.QueryChannelRange{
|
assertMsgSent(t, extraPeer, &lnwire.QueryChannelRange{
|
||||||
FirstBlockHeight: 0,
|
FirstBlockHeight: 0,
|
||||||
NumBlocks: math.MaxUint32,
|
NumBlocks: latestKnownHeight,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +328,7 @@ func TestSyncManagerGraphSyncedAfterHistoricalSyncReplacement(t *testing.T) {
|
|||||||
syncMgr.InitSyncState(peer)
|
syncMgr.InitSyncState(peer)
|
||||||
assertMsgSent(t, peer, &lnwire.QueryChannelRange{
|
assertMsgSent(t, peer, &lnwire.QueryChannelRange{
|
||||||
FirstBlockHeight: 0,
|
FirstBlockHeight: 0,
|
||||||
NumBlocks: math.MaxUint32,
|
NumBlocks: latestKnownHeight,
|
||||||
})
|
})
|
||||||
|
|
||||||
// The graph should not be considered as synced since the initial
|
// The graph should not be considered as synced since the initial
|
||||||
@ -531,7 +533,7 @@ func assertTransitionToChansSynced(t *testing.T, s *GossipSyncer, peer *mockPeer
|
|||||||
|
|
||||||
query := &lnwire.QueryChannelRange{
|
query := &lnwire.QueryChannelRange{
|
||||||
FirstBlockHeight: 0,
|
FirstBlockHeight: 0,
|
||||||
NumBlocks: math.MaxUint32,
|
NumBlocks: latestKnownHeight,
|
||||||
}
|
}
|
||||||
assertMsgSent(t, peer, query)
|
assertMsgSent(t, peer, query)
|
||||||
|
|
||||||
|
@ -237,6 +237,9 @@ type gossipSyncerCfg struct {
|
|||||||
// This prevents ranges with old start times from causing us to dump the
|
// This prevents ranges with old start times from causing us to dump the
|
||||||
// graph on connect.
|
// graph on connect.
|
||||||
ignoreHistoricalFilters bool
|
ignoreHistoricalFilters bool
|
||||||
|
|
||||||
|
// bestHeight returns the latest height known of the chain.
|
||||||
|
bestHeight func() uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// GossipSyncer is a struct that handles synchronizing the channel graph state
|
// GossipSyncer is a struct that handles synchronizing the channel graph state
|
||||||
@ -834,9 +837,17 @@ func (g *GossipSyncer) genChanRangeQuery(
|
|||||||
startHeight = uint32(newestChan.BlockHeight - chanRangeQueryBuffer)
|
startHeight = uint32(newestChan.BlockHeight - chanRangeQueryBuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine the number of blocks to request based on our best height.
|
||||||
|
// We'll take into account any potential underflows and explicitly set
|
||||||
|
// numBlocks to its minimum value of 1 if so.
|
||||||
|
bestHeight := g.cfg.bestHeight()
|
||||||
|
numBlocks := bestHeight - startHeight
|
||||||
|
if int64(numBlocks) < 1 {
|
||||||
|
numBlocks = 1
|
||||||
|
}
|
||||||
|
|
||||||
log.Infof("GossipSyncer(%x): requesting new chans from height=%v "+
|
log.Infof("GossipSyncer(%x): requesting new chans from height=%v "+
|
||||||
"and %v blocks after", g.cfg.peerPub[:], startHeight,
|
"and %v blocks after", g.cfg.peerPub[:], startHeight, numBlocks)
|
||||||
math.MaxUint32-startHeight)
|
|
||||||
|
|
||||||
// Finally, we'll craft the channel range query, using our starting
|
// Finally, we'll craft the channel range query, using our starting
|
||||||
// height, then asking for all known channels to the foreseeable end of
|
// height, then asking for all known channels to the foreseeable end of
|
||||||
@ -844,7 +855,7 @@ func (g *GossipSyncer) genChanRangeQuery(
|
|||||||
query := &lnwire.QueryChannelRange{
|
query := &lnwire.QueryChannelRange{
|
||||||
ChainHash: g.cfg.chainHash,
|
ChainHash: g.cfg.chainHash,
|
||||||
FirstBlockHeight: startHeight,
|
FirstBlockHeight: startHeight,
|
||||||
NumBlocks: math.MaxUint32 - startHeight,
|
NumBlocks: numBlocks,
|
||||||
}
|
}
|
||||||
g.curQueryRangeMsg = query
|
g.curQueryRangeMsg = query
|
||||||
|
|
||||||
|
@ -158,6 +158,9 @@ func newTestSyncer(hID lnwire.ShortChannelID,
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
delayedQueryReplyInterval: 2 * time.Second,
|
delayedQueryReplyInterval: 2 * time.Second,
|
||||||
|
bestHeight: func() uint32 {
|
||||||
|
return latestKnownHeight
|
||||||
|
},
|
||||||
}
|
}
|
||||||
syncer := newGossipSyncer(cfg)
|
syncer := newGossipSyncer(cfg)
|
||||||
|
|
||||||
@ -1134,9 +1137,9 @@ func TestGossipSyncerGenChanRangeQuery(t *testing.T) {
|
|||||||
rangeQuery.FirstBlockHeight,
|
rangeQuery.FirstBlockHeight,
|
||||||
startingHeight-chanRangeQueryBuffer)
|
startingHeight-chanRangeQueryBuffer)
|
||||||
}
|
}
|
||||||
if rangeQuery.NumBlocks != math.MaxUint32-firstHeight {
|
if rangeQuery.NumBlocks != latestKnownHeight-firstHeight {
|
||||||
t.Fatalf("wrong num blocks: expected %v, got %v",
|
t.Fatalf("wrong num blocks: expected %v, got %v",
|
||||||
math.MaxUint32-firstHeight, rangeQuery.NumBlocks)
|
latestKnownHeight-firstHeight, rangeQuery.NumBlocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generating a historical range query should result in a start height
|
// Generating a historical range query should result in a start height
|
||||||
@ -1149,9 +1152,9 @@ func TestGossipSyncerGenChanRangeQuery(t *testing.T) {
|
|||||||
t.Fatalf("incorrect chan range query: expected %v, %v", 0,
|
t.Fatalf("incorrect chan range query: expected %v, %v", 0,
|
||||||
rangeQuery.FirstBlockHeight)
|
rangeQuery.FirstBlockHeight)
|
||||||
}
|
}
|
||||||
if rangeQuery.NumBlocks != math.MaxUint32 {
|
if rangeQuery.NumBlocks != latestKnownHeight {
|
||||||
t.Fatalf("wrong num blocks: expected %v, got %v",
|
t.Fatalf("wrong num blocks: expected %v, got %v",
|
||||||
math.MaxUint32, rangeQuery.NumBlocks)
|
latestKnownHeight, rangeQuery.NumBlocks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2234,7 +2237,7 @@ func TestGossipSyncerHistoricalSync(t *testing.T) {
|
|||||||
// sent to the remote peer with a FirstBlockHeight of 0.
|
// sent to the remote peer with a FirstBlockHeight of 0.
|
||||||
expectedMsg := &lnwire.QueryChannelRange{
|
expectedMsg := &lnwire.QueryChannelRange{
|
||||||
FirstBlockHeight: 0,
|
FirstBlockHeight: 0,
|
||||||
NumBlocks: math.MaxUint32,
|
NumBlocks: latestKnownHeight,
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
Loading…
Reference in New Issue
Block a user