Merge pull request #6054 from yyforyongyu/itest-fix-gossiper

discovery: resend premature messages when block height reached
This commit is contained in:
Olaoluwa Osuntokun authored and GitHub committed 2022-01-04 17:52:18 -08:00
commit ebc1547abc
10 files changed
+303 -78

No files matched your search

+4 -4
View File
@@ -614,8 +614,8 @@ func (n *TxNotifier) RegisterConf(txid *chainhash.Hash, pkScript []byte,
if err == nil { if err == nil {
if hint > startHeight { if hint > startHeight {
Log.Debugf("Using height hint %d retrieved from cache "+ Log.Debugf("Using height hint %d retrieved from cache "+
"for %v instead of %d", hint, ntfn.ConfRequest, "for %v instead of %d for conf subscription",
startHeight) hint, ntfn.ConfRequest, startHeight)
startHeight = hint startHeight = hint
} }
} else if err != ErrConfirmHintNotFound { } else if err != ErrConfirmHintNotFound {
@@ -1009,8 +1009,8 @@ func (n *TxNotifier) RegisterSpend(outpoint *wire.OutPoint, pkScript []byte,
if err == nil { if err == nil {
if hint > startHeight { if hint > startHeight {
Log.Debugf("Using height hint %d retrieved from cache "+ Log.Debugf("Using height hint %d retrieved from cache "+
"for %v instead of %d", hint, ntfn.SpendRequest, "for %v instead of %d for spend subscription",
startHeight) hint, ntfn.SpendRequest, startHeight)
startHeight = hint startHeight = hint
} }
} else if err != ErrSpendHintNotFound { } else if err != ErrSpendHintNotFound {
+233 -51
View File
@@ -309,6 +309,14 @@ func newRejectCacheKey(cid uint64, pub [33]byte) rejectCacheKey {
return k return k
} }
// sourceToPub returns a serialized-compressed public key for use in the reject
// cache.
func sourceToPub(pk *btcec.PublicKey) [33]byte {
var pub [33]byte
copy(pub[:], pk.SerializeCompressed())
return pub
}
// cachedReject is the empty value used to track the value for rejects. // cachedReject is the empty value used to track the value for rejects.
type cachedReject struct { type cachedReject struct {
} }
@@ -360,6 +368,13 @@ type AuthenticatedGossiper struct {
// networkHandler. // networkHandler.
networkMsgs chan *networkMsg networkMsgs chan *networkMsg
// futureMsgs is a list of premature network messages that have a block
// height specified in the future. We will save them and resend it to
// the chan networkMsgs once the block height has reached. The cached
// map format is,
// {blockHeight: [msg1, msg2, ...], ...}
futureMsgs *lru.Cache
// chanPolicyUpdates is a channel that requests to update the // chanPolicyUpdates is a channel that requests to update the
// forwarding policy of a set of channels is sent over. // forwarding policy of a set of channels is sent over.
chanPolicyUpdates chan *chanPolicyUpdateRequest chanPolicyUpdates chan *chanPolicyUpdateRequest
@@ -415,6 +430,7 @@ func New(cfg Config, selfKeyDesc *keychain.KeyDescriptor) *AuthenticatedGossiper
selfKeyLoc: selfKeyDesc.KeyLocator, selfKeyLoc: selfKeyDesc.KeyLocator,
cfg: &cfg, cfg: &cfg,
networkMsgs: make(chan *networkMsg), networkMsgs: make(chan *networkMsg),
futureMsgs: lru.NewCache(maxPrematureUpdates),
quit: make(chan struct{}), quit: make(chan struct{}),
chanPolicyUpdates: make(chan *chanPolicyUpdateRequest), chanPolicyUpdates: make(chan *chanPolicyUpdateRequest),
prematureChannelUpdates: lru.NewCache(maxPrematureUpdates), prematureChannelUpdates: lru.NewCache(maxPrematureUpdates),
@@ -514,12 +530,82 @@ func (d *AuthenticatedGossiper) start() error {
d.syncMgr.Start() d.syncMgr.Start()
d.wg.Add(1) // Start receiving blocks in its dedicated goroutine.
d.wg.Add(2)
go d.syncBlockHeight()
go d.networkHandler() go d.networkHandler()
return nil return nil
} }
// syncBlockHeight syncs the best block height for the gossiper by reading
// blockEpochs.
//
// NOTE: must be run as a goroutine.
func (d *AuthenticatedGossiper) syncBlockHeight() {
defer d.wg.Done()
for {
select {
// A new block has arrived, so we can re-process the previously
// premature announcements.
case newBlock, ok := <-d.blockEpochs.Epochs:
// If the channel has been closed, then this indicates
// the daemon is shutting down, so we exit ourselves.
if !ok {
return
}
// Once a new block arrives, we update our running
// track of the height of the chain tip.
d.Lock()
blockHeight := uint32(newBlock.Height)
d.bestHeight = blockHeight
d.Unlock()
log.Debugf("New block: height=%d, hash=%s", blockHeight,
newBlock.Hash)
// Resend future messages, if any.
d.resendFutureMessages(blockHeight)
case <-d.quit:
return
}
}
}
// resendFutureMessages takes a block height, resends all the future messages
// found at that height and deletes those messages found in the gossiper's
// futureMsgs.
func (d *AuthenticatedGossiper) resendFutureMessages(height uint32) {
result, err := d.futureMsgs.Get(height)
// Return early if no messages found.
if err == cache.ErrElementNotFound {
return
}
// The error must nil, we will log an error and exit.
if err != nil {
log.Errorf("Reading future messages got error: %v", err)
return
}
msgs := result.(*cachedNetworkMsg).msgs
log.Debugf("Resending %d network messages at height %d",
len(msgs), height)
for _, msg := range msgs {
select {
case d.networkMsgs <- msg:
case <-d.quit:
msg.err <- ErrGossiperShuttingDown
}
}
}
// Stop signals any active goroutines for a graceful closure. // Stop signals any active goroutines for a graceful closure.
func (d *AuthenticatedGossiper) Stop() error { func (d *AuthenticatedGossiper) Stop() error {
d.stopped.Do(func() { d.stopped.Do(func() {
@@ -757,6 +843,8 @@ func (d *deDupedAnnouncements) reset() {
// and the set of senders is updated to reflect which node sent us this // and the set of senders is updated to reflect which node sent us this
// message. // message.
func (d *deDupedAnnouncements) addMsg(message networkMsg) { func (d *deDupedAnnouncements) addMsg(message networkMsg) {
log.Tracef("Adding network message: %v to batch", message.msg.MsgType())
// Depending on the message type (channel announcement, channel update, // Depending on the message type (channel announcement, channel update,
// or node announcement), the message is added to the corresponding map // or node announcement), the message is added to the corresponding map
// in deDupedAnnouncements. Because each identifying key can have at // in deDupedAnnouncements. Because each identifying key can have at
@@ -806,6 +894,10 @@ func (d *deDupedAnnouncements) addMsg(message networkMsg) {
// If we already had this message with a strictly newer // If we already had this message with a strictly newer
// timestamp, then we'll just discard the message we got. // timestamp, then we'll just discard the message we got.
if oldTimestamp > msg.Timestamp { if oldTimestamp > msg.Timestamp {
log.Debugf("Ignored outdated network message: "+
"peer=%v, source=%x, msg=%s, ", message.peer,
message.source.SerializeCompressed(),
msg.MsgType())
return return
} }
@@ -1025,6 +1117,9 @@ func (d *AuthenticatedGossiper) networkHandler() {
// sub-systems below us, then craft, sign, and broadcast a new // sub-systems below us, then craft, sign, and broadcast a new
// ChannelUpdate for the set of affected clients. // ChannelUpdate for the set of affected clients.
case policyUpdate := <-d.chanPolicyUpdates: case policyUpdate := <-d.chanPolicyUpdates:
log.Tracef("Received channel %d policy update requests",
len(policyUpdate.edgesToUpdate))
// First, we'll now create new fully signed updates for // First, we'll now create new fully signed updates for
// the affected channels and also update the underlying // the affected channels and also update the underlying
// graph with the new state. // graph with the new state.
@@ -1044,6 +1139,13 @@ func (d *AuthenticatedGossiper) networkHandler() {
announcements.AddMsgs(newChanUpdates...) announcements.AddMsgs(newChanUpdates...)
case announcement := <-d.networkMsgs: case announcement := <-d.networkMsgs:
log.Tracef("Received network message: "+
"peer=%v, source=%x, msg=%s, is_remote=%v",
announcement.peer,
announcement.source.SerializeCompressed(),
announcement.msg.MsgType(),
announcement.isRemote)
// We should only broadcast this message forward if it // We should only broadcast this message forward if it
// originated from us or it wasn't received as part of // originated from us or it wasn't received as part of
// our initial historical sync. // our initial historical sync.
@@ -1057,6 +1159,11 @@ func (d *AuthenticatedGossiper) networkHandler() {
emittedAnnouncements, _ := d.processNetworkAnnouncement( emittedAnnouncements, _ := d.processNetworkAnnouncement(
announcement, announcement,
) )
log.Debugf("Processed network message %s, "+
"returned len(announcements)=%v",
announcement.msg.MsgType(),
len(emittedAnnouncements))
if emittedAnnouncements != nil { if emittedAnnouncements != nil {
announcements.AddMsgs( announcements.AddMsgs(
emittedAnnouncements..., emittedAnnouncements...,
@@ -1068,7 +1175,8 @@ func (d *AuthenticatedGossiper) networkHandler() {
// If this message was recently rejected, then we won't // If this message was recently rejected, then we won't
// attempt to re-process it. // attempt to re-process it.
if announcement.isRemote && d.isRecentlyRejectedMsg( if announcement.isRemote && d.isRecentlyRejectedMsg(
announcement.msg, announcement.peer.PubKey(), announcement.msg,
sourceToPub(announcement.source),
) { ) {
announcement.err <- fmt.Errorf("recently " + announcement.err <- fmt.Errorf("recently " +
"rejected") "rejected")
@@ -1092,8 +1200,11 @@ func (d *AuthenticatedGossiper) networkHandler() {
announcement.msg, announcement.msg,
) )
if err != nil { if err != nil {
if err != routing.ErrVBarrierShuttingDown && if !routing.IsError(
err != routing.ErrParentValidationFailed { err,
routing.ErrVBarrierShuttingDown,
routing.ErrParentValidationFailed,
) {
log.Warnf("unexpected error "+ log.Warnf("unexpected error "+
"during validation "+ "during validation "+
"barrier shutdown: %v", "barrier shutdown: %v",
@@ -1111,6 +1222,13 @@ func (d *AuthenticatedGossiper) networkHandler() {
announcement, announcement,
) )
log.Tracef("Processed network message %s, "+
"returned len(announcements)=%v, "+
"allowDependents=%v",
announcement.msg.MsgType(),
len(emittedAnnouncements),
allowDependents)
// If this message had any dependencies, then // If this message had any dependencies, then
// we can now signal them to continue. // we can now signal them to continue.
validationBarrier.SignalDependants( validationBarrier.SignalDependants(
@@ -1135,25 +1253,6 @@ func (d *AuthenticatedGossiper) networkHandler() {
}() }()
// A new block has arrived, so we can re-process the previously
// premature announcements.
case newBlock, ok := <-d.blockEpochs.Epochs:
// If the channel has been closed, then this indicates
// the daemon is shutting down, so we exit ourselves.
if !ok {
return
}
// Once a new block arrives, we update our running
// track of the height of the chain tip.
d.Lock()
blockHeight := uint32(newBlock.Height)
d.bestHeight = blockHeight
d.Unlock()
log.Debugf("New block: height=%d, hash=%s", blockHeight,
newBlock.Hash)
// The trickle timer has ticked, which indicates we should // The trickle timer has ticked, which indicates we should
// flush to the network the pending batch of new announcements // flush to the network the pending batch of new announcements
// we've received since the last trickle tick. // we've received since the last trickle tick.
@@ -1579,6 +1678,64 @@ func (d *AuthenticatedGossiper) addNode(msg *lnwire.NodeAnnouncement,
return d.cfg.Router.AddNode(node, op...) return d.cfg.Router.AddNode(node, op...)
} }
// isPremature decides whether a given network message has a block height+delta
// value specified in the future. If so, the message will be added to the
// future message map and be processed when the block height as reached.
//
// NOTE: must be used inside a lock.
func (d *AuthenticatedGossiper) isPremature(chanID lnwire.ShortChannelID,
delta uint32, msg *networkMsg) bool {
// TODO(roasbeef) make height delta 6
// * or configurable
msgHeight := chanID.BlockHeight + delta
// The message height is smaller or equal to our best known height,
// thus the message is mature.
if msgHeight <= d.bestHeight {
return false
}
// Add the premature message to our future messages which will
// be resent once the block height has reached.
//
// Init an empty cached message and overwrite it if there are cached
// messages found.
cachedMsgs := &cachedNetworkMsg{
msgs: make([]*networkMsg, 0),
}
result, err := d.futureMsgs.Get(msgHeight)
// No error returned means we have old messages cached.
if err == nil {
cachedMsgs = result.(*cachedNetworkMsg)
}
// Copy the networkMsgs since the old message's err chan will
// be consumed.
copied := &networkMsg{
peer: msg.peer,
source: msg.source,
msg: msg.msg,
optionalMsgFields: msg.optionalMsgFields,
isRemote: msg.isRemote,
err: make(chan error, 1),
}
// Add the network message.
cachedMsgs.msgs = append(cachedMsgs.msgs, copied)
_, err = d.futureMsgs.Put(msgHeight, cachedMsgs)
if err != nil {
log.Errorf("Adding future message got error: %v", err)
}
log.Debugf("Network message: %v added to future messages for "+
"msgHeight=%d, bestHeight=%d", msg.msg.MsgType(),
msgHeight, d.bestHeight)
return true
}
// processNetworkAnnouncement processes a new network relate authenticated // processNetworkAnnouncement processes a new network relate authenticated
// channel or node announcement or announcements proofs. If the announcement // channel or node announcement or announcements proofs. If the announcement
// didn't affect the internal state due to either being out of date, invalid, // didn't affect the internal state due to either being out of date, invalid,
@@ -1589,11 +1746,9 @@ func (d *AuthenticatedGossiper) addNode(msg *lnwire.NodeAnnouncement,
func (d *AuthenticatedGossiper) processNetworkAnnouncement( func (d *AuthenticatedGossiper) processNetworkAnnouncement(
nMsg *networkMsg) ([]networkMsg, bool) { nMsg *networkMsg) ([]networkMsg, bool) {
isPremature := func(chanID lnwire.ShortChannelID, delta uint32) bool { log.Debugf("Processing network message: peer=%v, source=%x, msg=%s, "+
// TODO(roasbeef) make height delta 6 "is_remote=%v", nMsg.peer, nMsg.source.SerializeCompressed(),
// * or configurable nMsg.msg.MsgType(), nMsg.isRemote)
return chanID.BlockHeight+delta > d.bestHeight
}
// If this is a remote update, we set the scheduler option to lazily // If this is a remote update, we set the scheduler option to lazily
// add it to the graph. // add it to the graph.
@@ -1616,16 +1771,22 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
// newer update for this node so we can skip validating // newer update for this node so we can skip validating
// signatures if not required. // signatures if not required.
if d.cfg.Router.IsStaleNode(msg.NodeID, timestamp) { if d.cfg.Router.IsStaleNode(msg.NodeID, timestamp) {
log.Debugf("Skipped processing stale node: %x",
msg.NodeID)
nMsg.err <- nil nMsg.err <- nil
return nil, true return nil, true
} }
if err := d.addNode(msg, schedulerOp...); err != nil { if err := d.addNode(msg, schedulerOp...); err != nil {
if routing.IsError(err, routing.ErrOutdated, log.Debugf("Adding node: %x got error: %v",
routing.ErrIgnored) { msg.NodeID, err)
log.Debug(err) if !routing.IsError(
} else if err != routing.ErrVBarrierShuttingDown { err,
routing.ErrOutdated,
routing.ErrIgnored,
routing.ErrVBarrierShuttingDown,
) {
log.Error(err) log.Error(err)
} }
@@ -1676,7 +1837,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
key := newRejectCacheKey( key := newRejectCacheKey(
msg.ShortChannelID.ToUint64(), msg.ShortChannelID.ToUint64(),
nMsg.peer.PubKey(), sourceToPub(nMsg.source),
) )
_, _ = d.recentRejects.Put(key, &cachedReject{}) _, _ = d.recentRejects.Put(key, &cachedReject{})
@@ -1687,8 +1848,8 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
// If the advertised inclusionary block is beyond our knowledge // If the advertised inclusionary block is beyond our knowledge
// of the chain tip, then we'll ignore for it now. // of the chain tip, then we'll ignore for it now.
d.Lock() d.Lock()
if nMsg.isRemote && isPremature(msg.ShortChannelID, 0) { if nMsg.isRemote && d.isPremature(msg.ShortChannelID, 0, nMsg) {
log.Infof("Announcement for chan_id=(%v), is "+ log.Warnf("Announcement for chan_id=(%v), is "+
"premature: advertises height %v, only "+ "premature: advertises height %v, only "+
"height %v is known", "height %v is known",
msg.ShortChannelID.ToUint64(), msg.ShortChannelID.ToUint64(),
@@ -1719,7 +1880,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
key := newRejectCacheKey( key := newRejectCacheKey(
msg.ShortChannelID.ToUint64(), msg.ShortChannelID.ToUint64(),
nMsg.peer.PubKey(), sourceToPub(nMsg.source),
) )
_, _ = d.recentRejects.Put(key, &cachedReject{}) _, _ = d.recentRejects.Put(key, &cachedReject{})
@@ -1782,8 +1943,10 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
// making decisions based on this DB state, before it // making decisions based on this DB state, before it
// writes to the DB. // writes to the DB.
d.channelMtx.Lock(msg.ShortChannelID.ToUint64()) d.channelMtx.Lock(msg.ShortChannelID.ToUint64())
defer d.channelMtx.Unlock(msg.ShortChannelID.ToUint64()) err := d.cfg.Router.AddEdge(edge, schedulerOp...)
if err := d.cfg.Router.AddEdge(edge, schedulerOp...); err != nil { if err != nil {
defer d.channelMtx.Unlock(msg.ShortChannelID.ToUint64())
// If the edge was rejected due to already being known, // If the edge was rejected due to already being known,
// then it may be that case that this new message has a // then it may be that case that this new message has a
// fresh channel proof, so we'll check. // fresh channel proof, so we'll check.
@@ -1795,7 +1958,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
key := newRejectCacheKey( key := newRejectCacheKey(
msg.ShortChannelID.ToUint64(), msg.ShortChannelID.ToUint64(),
nMsg.peer.PubKey(), sourceToPub(nMsg.source),
) )
_, _ = d.recentRejects.Put(key, &cachedReject{}) _, _ = d.recentRejects.Put(key, &cachedReject{})
@@ -1817,12 +1980,12 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
log.Debugf("Router rejected channel "+ log.Debugf("Router rejected channel "+
"edge: %v", err) "edge: %v", err)
} else { } else {
log.Tracef("Router rejected channel "+ log.Debugf("Router rejected channel "+
"edge: %v", err) "edge: %v", err)
key := newRejectCacheKey( key := newRejectCacheKey(
msg.ShortChannelID.ToUint64(), msg.ShortChannelID.ToUint64(),
nMsg.peer.PubKey(), sourceToPub(nMsg.source),
) )
_, _ = d.recentRejects.Put(key, &cachedReject{}) _, _ = d.recentRejects.Put(key, &cachedReject{})
} }
@@ -1831,6 +1994,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
return nil, false return nil, false
} }
// If err is nil, release the lock immediately.
d.channelMtx.Unlock(msg.ShortChannelID.ToUint64())
// If we earlier received any ChannelUpdates for this channel, // If we earlier received any ChannelUpdates for this channel,
// we can now process them, as the channel is added to the // we can now process them, as the channel is added to the
// graph. // graph.
@@ -1909,7 +2075,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
key := newRejectCacheKey( key := newRejectCacheKey(
msg.ShortChannelID.ToUint64(), msg.ShortChannelID.ToUint64(),
nMsg.peer.PubKey(), sourceToPub(nMsg.source),
) )
_, _ = d.recentRejects.Put(key, &cachedReject{}) _, _ = d.recentRejects.Put(key, &cachedReject{})
@@ -1924,8 +2090,8 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
// of the chain tip, then we'll put the announcement in limbo // of the chain tip, then we'll put the announcement in limbo
// to be fully verified once we advance forward in the chain. // to be fully verified once we advance forward in the chain.
d.Lock() d.Lock()
if nMsg.isRemote && isPremature(msg.ShortChannelID, 0) { if nMsg.isRemote && d.isPremature(msg.ShortChannelID, 0, nMsg) {
log.Infof("Update announcement for "+ log.Warnf("Update announcement for "+
"short_chan_id(%v), is premature: advertises "+ "short_chan_id(%v), is premature: advertises "+
"height %v, only height %v is known", "height %v, only height %v is known",
shortChanID, blockHeight, shortChanID, blockHeight,
@@ -1943,6 +2109,12 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
if d.cfg.Router.IsStaleEdgePolicy( if d.cfg.Router.IsStaleEdgePolicy(
msg.ShortChannelID, timestamp, msg.ChannelFlags, msg.ShortChannelID, timestamp, msg.ChannelFlags,
) { ) {
log.Debugf("Ignored stale edge policy: peer=%v, "+
"source=%x, msg=%s, is_remote=%v", nMsg.peer,
nMsg.source.SerializeCompressed(),
nMsg.msg.MsgType(), nMsg.isRemote)
nMsg.err <- nil nMsg.err <- nil
return nil, true return nil, true
} }
@@ -2035,7 +2207,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
key := newRejectCacheKey( key := newRejectCacheKey(
msg.ShortChannelID.ToUint64(), msg.ShortChannelID.ToUint64(),
nMsg.peer.PubKey(), sourceToPub(nMsg.source),
) )
_, _ = d.recentRejects.Put(key, &cachedReject{}) _, _ = d.recentRejects.Put(key, &cachedReject{})
@@ -2137,14 +2309,17 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
} }
if err := d.cfg.Router.UpdateEdge(update, schedulerOp...); err != nil { if err := d.cfg.Router.UpdateEdge(update, schedulerOp...); err != nil {
if routing.IsError(err, routing.ErrOutdated, if routing.IsError(
routing.ErrIgnored) { err, routing.ErrOutdated,
routing.ErrIgnored,
routing.ErrVBarrierShuttingDown,
) {
log.Debug(err) log.Debug(err)
} else if err != routing.ErrVBarrierShuttingDown {
} else {
key := newRejectCacheKey( key := newRejectCacheKey(
msg.ShortChannelID.ToUint64(), msg.ShortChannelID.ToUint64(),
nMsg.peer.PubKey(), sourceToPub(nMsg.source),
) )
_, _ = d.recentRejects.Put(key, &cachedReject{}) _, _ = d.recentRejects.Put(key, &cachedReject{})
@@ -2166,6 +2341,10 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
chanInfo, msg.ChannelFlags, chanInfo, msg.ChannelFlags,
) )
log.Debugf("The message %v has no AuthProof, sending "+
"the update to remote peer %x",
msg.MsgType(), remotePubKey)
// Now, we'll attempt to send the channel update message // Now, we'll attempt to send the channel update message
// reliably to the remote peer in the background, so // reliably to the remote peer in the background, so
// that we don't block if the peer happens to be offline // that we don't block if the peer happens to be offline
@@ -2217,8 +2396,11 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
// registered in bitcoin blockchain. Therefore, we check if the // registered in bitcoin blockchain. Therefore, we check if the
// proof is premature. // proof is premature.
d.Lock() d.Lock()
if isPremature(msg.ShortChannelID, d.cfg.ProofMatureDelta) { premature := d.isPremature(
log.Infof("Premature proof announcement, current "+ msg.ShortChannelID, d.cfg.ProofMatureDelta, nMsg,
)
if premature {
log.Warnf("Premature proof announcement, current "+
"block height lower than needed: %v < %v", "block height lower than needed: %v < %v",
d.bestHeight, needBlockHeight) d.bestHeight, needBlockHeight)
d.Unlock() d.Unlock()
+8 -3
View File
@@ -131,10 +131,10 @@ spawnHandler:
// spawnPeerMsgHandler spawns a peerHandler for the given peer if there isn't // spawnPeerMsgHandler spawns a peerHandler for the given peer if there isn't
// one already active. The boolean returned signals whether there was already // one already active. The boolean returned signals whether there was already
// one active or not. // one active or not.
func (s *reliableSender) spawnPeerHandler(peerPubKey [33]byte) (peerManager, bool) { func (s *reliableSender) spawnPeerHandler(
s.activePeersMtx.Lock() peerPubKey [33]byte) (peerManager, bool) {
defer s.activePeersMtx.Unlock()
s.activePeersMtx.Lock()
msgHandler, ok := s.activePeers[peerPubKey] msgHandler, ok := s.activePeers[peerPubKey]
if !ok { if !ok {
msgHandler = peerManager{ msgHandler = peerManager{
@@ -142,7 +142,12 @@ func (s *reliableSender) spawnPeerHandler(peerPubKey [33]byte) (peerManager, boo
done: make(chan struct{}), done: make(chan struct{}),
} }
s.activePeers[peerPubKey] = msgHandler s.activePeers[peerPubKey] = msgHandler
}
s.activePeersMtx.Unlock()
// If this is a newly initiated peerManager, we will create a
// peerHandler.
if !ok {
s.wg.Add(1) s.wg.Add(1)
go s.peerHandler(msgHandler, peerPubKey) go s.peerHandler(msgHandler, peerPubKey)
} }
+11
View File
@@ -398,6 +398,13 @@ func (m *SyncManager) syncerHandler() {
continue continue
} }
// We may not even have enough inactive syncers to be
// transitted. In that case, we will transit all the
// inactive syncers.
if len(m.inactiveSyncers) < numActiveLeft {
numActiveLeft = len(m.inactiveSyncers)
}
log.Debugf("Attempting to transition %v passive "+ log.Debugf("Attempting to transition %v passive "+
"GossipSyncers to active", numActiveLeft) "GossipSyncers to active", numActiveLeft)
@@ -492,6 +499,10 @@ func (m *SyncManager) createGossipSyncer(peer lnpeer.Peer) *GossipSyncer {
// handle any sync transitions. // handle any sync transitions.
s.setSyncState(chansSynced) s.setSyncState(chansSynced)
s.setSyncType(PassiveSync) s.setSyncType(PassiveSync)
log.Debugf("Created new GossipSyncer[state=%s type=%s] for peer=%v",
s.syncState(), s.SyncType(), peer)
return s return s
} }
@@ -18,6 +18,11 @@
due to the cancel signal is processed before the creation. It is now properly due to the cancel signal is processed before the creation. It is now properly
handled by moving creation before deletion. handled by moving creation before deletion.
* When the block height+delta specified by a network message is greater than
the gossiper's best height, it will be considered as premature and ignored.
[These premature messages are now saved into a cache and processed once the
height has reached.](https://github.com/lightningnetwork/lnd/pull/6054)
## Misc ## Misc
* [An example systemd service file](https://github.com/lightningnetwork/lnd/pull/6033) * [An example systemd service file](https://github.com/lightningnetwork/lnd/pull/6033)
+14 -1
View File
@@ -553,6 +553,19 @@ const (
addedToRouterGraph addedToRouterGraph
) )
func (c channelOpeningState) String() string {
switch c {
case markedOpen:
return "markedOpen"
case fundingLockedSent:
return "fundingLocked"
case addedToRouterGraph:
return "addedToRouterGraph"
default:
return "unknown"
}
}
// NewFundingManager creates and initializes a new instance of the // NewFundingManager creates and initializes a new instance of the
// fundingManager. // fundingManager.
func NewFundingManager(cfg Config) (*Manager, error) { func NewFundingManager(cfg Config) (*Manager, error) {
@@ -2773,7 +2786,7 @@ func (f *Manager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
} }
log.Debugf("Channel with ChannelPoint(%v), short_chan_id=%v "+ log.Debugf("Channel with ChannelPoint(%v), short_chan_id=%v "+
"announced", &fundingPoint, shortChanID) "sent to gossiper", &fundingPoint, shortChanID)
} }
return nil return nil
+9
View File
@@ -28,6 +28,15 @@ const (
// ErrInvalidFundingOutput is returned if the channle funding output // ErrInvalidFundingOutput is returned if the channle funding output
// fails validation. // fails validation.
ErrInvalidFundingOutput ErrInvalidFundingOutput
// ErrVBarrierShuttingDown signals that the barrier has been requested
// to shutdown, and that the caller should not treat the wait condition
// as fulfilled.
ErrVBarrierShuttingDown
// ErrParentValidationFailed signals that the validation of a
// dependent's parent failed, so the dependent must not be processed.
ErrParentValidationFailed
) )
// routerError is a structure that represent the error inside the routing package, // routerError is a structure that represent the error inside the routing package,
+9 -3
View File
@@ -1062,13 +1062,19 @@ func (r *ChannelRouter) networkHandler() {
update.msg, update.msg,
) )
if err != nil { if err != nil {
switch err { switch {
case ErrVBarrierShuttingDown: case IsError(
err, ErrVBarrierShuttingDown,
):
update.err <- err update.err <- err
case ErrParentValidationFailed:
case IsError(
err, ErrParentValidationFailed,
):
update.err <- newErrf( update.err <- newErrf(
ErrIgnored, err.Error(), ErrIgnored, err.Error(),
) )
default: default:
log.Warnf("unexpected error "+ log.Warnf("unexpected error "+
"during validation "+ "during validation "+
+4 -14
View File
@@ -1,7 +1,6 @@
package routing package routing
import ( import (
"errors"
"sync" "sync"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
@@ -9,17 +8,6 @@ import (
"github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/routing/route"
) )
var (
// ErrVBarrierShuttingDown signals that the barrier has been requested
// to shutdown, and that the caller should not treat the wait condition
// as fulfilled.
ErrVBarrierShuttingDown = errors.New("validation barrier shutting down")
// ErrParentValidationFailed signals that the validation of a
// dependent's parent failed, so the dependent must not be processed.
ErrParentValidationFailed = errors.New("parent validation failed")
)
// validationSignals contains two signals which allows the ValidationBarrier to // validationSignals contains two signals which allows the ValidationBarrier to
// communicate back to the caller whether a dependent should be processed or not // communicate back to the caller whether a dependent should be processed or not
// based on whether its parent was successfully validated. Only one of these // based on whether its parent was successfully validated. Only one of these
@@ -228,9 +216,11 @@ func (v *ValidationBarrier) WaitForDependants(job interface{}) error {
if ok { if ok {
select { select {
case <-v.quit: case <-v.quit:
return ErrVBarrierShuttingDown return newErrf(ErrVBarrierShuttingDown,
"validation barrier shutting down")
case <-signals.deny: case <-signals.deny:
return ErrParentValidationFailed return newErrf(ErrParentValidationFailed,
"parent validation failed")
case <-signals.allow: case <-signals.allow:
return nil return nil
} }
+6 -2
View File
@@ -141,14 +141,18 @@ func TestValidationBarrierQuit(t *testing.T) {
switch { switch {
// First half should return without failure. // First half should return without failure.
case i < numTasks/4 && err != routing.ErrParentValidationFailed: case i < numTasks/4 && !routing.IsError(
err, routing.ErrParentValidationFailed,
):
t.Fatalf("unexpected failure while waiting: %v", err) t.Fatalf("unexpected failure while waiting: %v", err)
case i >= numTasks/4 && i < numTasks/2 && err != nil: case i >= numTasks/4 && i < numTasks/2 && err != nil:
t.Fatalf("unexpected failure while waiting: %v", err) t.Fatalf("unexpected failure while waiting: %v", err)
// Last half should return the shutdown error. // Last half should return the shutdown error.
case i >= numTasks/2 && err != routing.ErrVBarrierShuttingDown: case i >= numTasks/2 && !routing.IsError(
err, routing.ErrVBarrierShuttingDown,
):
t.Fatalf("expected failure after quitting: want %v, "+ t.Fatalf("expected failure after quitting: want %v, "+
"got %v", routing.ErrVBarrierShuttingDown, err) "got %v", routing.ErrVBarrierShuttingDown, err)
} }