discovery: move ann sig handling to handleAnnSig

This commit is contained in:
eugene 2022-02-18 14:34:52 -05:00
parent 1e9220dab6
commit 932c5f1a7b
No known key found for this signature in database
GPG Key ID: 118759E83439A9B1

View File

@ -1758,10 +1758,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
schedulerOp = append(schedulerOp, batch.LazyAdd()) schedulerOp = append(schedulerOp, batch.LazyAdd())
} }
var announcements []networkMsg
switch msg := nMsg.msg.(type) { switch msg := nMsg.msg.(type) {
// A new node announcement has arrived which either presents new // A new node announcement has arrived which either presents new
// information about a node in one of the channels we know about, or a // information about a node in one of the channels we know about, or a
// updating previously advertised information. // updating previously advertised information.
@ -1785,324 +1782,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
// willingness of nodes involved in the funding of a channel to // willingness of nodes involved in the funding of a channel to
// announce this new channel to the rest of the world. // announce this new channel to the rest of the world.
case *lnwire.AnnounceSignatures: case *lnwire.AnnounceSignatures:
needBlockHeight := msg.ShortChannelID.BlockHeight + return d.handleAnnSig(nMsg, msg)
d.cfg.ProofMatureDelta
shortChanID := msg.ShortChannelID.ToUint64()
prefix := "local"
if nMsg.isRemote {
prefix = "remote"
}
log.Infof("Received new %v channel announcement for %v", prefix,
msg.ShortChannelID)
// By the specification, channel announcement proofs should be
// sent after some number of confirmations after channel was
// registered in bitcoin blockchain. Therefore, we check if the
// proof is premature.
d.Lock()
premature := d.isPremature(
msg.ShortChannelID, d.cfg.ProofMatureDelta, nMsg,
)
if premature {
log.Warnf("Premature proof announcement, current "+
"block height lower than needed: %v < %v",
d.bestHeight, needBlockHeight)
d.Unlock()
nMsg.err <- nil
return nil, false
}
d.Unlock()
// Ensure that we know of a channel with the target channel ID
// before proceeding further.
//
// We must acquire the mutex for this channel ID before getting
// the channel from the database, to ensure what we read does
// not change before we call AddProof() later.
d.channelMtx.Lock(msg.ShortChannelID.ToUint64())
defer d.channelMtx.Unlock(msg.ShortChannelID.ToUint64())
chanInfo, e1, e2, err := d.cfg.Router.GetChannelByID(
msg.ShortChannelID)
if err != nil {
// TODO(andrew.shvv) this is dangerous because remote
// node might rewrite the waiting proof.
proof := channeldb.NewWaitingProof(nMsg.isRemote, msg)
err := d.cfg.WaitingProofStore.Add(proof)
if err != nil {
err := fmt.Errorf("unable to store "+
"the proof for short_chan_id=%v: %v",
shortChanID, err)
log.Error(err)
nMsg.err <- err
return nil, false
}
log.Infof("Orphan %v proof announcement with "+
"short_chan_id=%v, adding "+
"to waiting batch", prefix, shortChanID)
nMsg.err <- nil
return nil, false
}
nodeID := nMsg.source.SerializeCompressed()
isFirstNode := bytes.Equal(nodeID, chanInfo.NodeKey1Bytes[:])
isSecondNode := bytes.Equal(nodeID, chanInfo.NodeKey2Bytes[:])
// Ensure that channel that was retrieved belongs to the peer
// which sent the proof announcement.
if !(isFirstNode || isSecondNode) {
err := fmt.Errorf("channel that was received not "+
"belongs to the peer which sent the proof, "+
"short_chan_id=%v", shortChanID)
log.Error(err)
nMsg.err <- err
return nil, false
}
// If proof was sent by a local sub-system, then we'll
// send the announcement signature to the remote node
// so they can also reconstruct the full channel
// announcement.
if !nMsg.isRemote {
var remotePubKey [33]byte
if isFirstNode {
remotePubKey = chanInfo.NodeKey2Bytes
} else {
remotePubKey = chanInfo.NodeKey1Bytes
}
// Since the remote peer might not be online
// we'll call a method that will attempt to
// deliver the proof when it comes online.
err := d.reliableSender.sendMessage(msg, remotePubKey)
if err != nil {
err := fmt.Errorf("unable to reliably send %v "+
"for channel=%v to peer=%x: %v",
msg.MsgType(), msg.ShortChannelID,
remotePubKey, err)
nMsg.err <- err
return nil, false
}
}
// Check if we already have the full proof for this channel.
if chanInfo.AuthProof != nil {
// If we already have the fully assembled proof, then
// the peer sending us their proof has probably not
// received our local proof yet. So be kind and send
// them the full proof.
if nMsg.isRemote {
peerID := nMsg.source.SerializeCompressed()
log.Debugf("Got AnnounceSignatures for " +
"channel with full proof.")
d.wg.Add(1)
go func() {
defer d.wg.Done()
log.Debugf("Received half proof for "+
"channel %v with existing "+
"full proof. Sending full "+
"proof to peer=%x",
msg.ChannelID,
peerID)
chanAnn, _, _, err := netann.CreateChanAnnouncement(
chanInfo.AuthProof, chanInfo,
e1, e2,
)
if err != nil {
log.Errorf("unable to gen "+
"ann: %v", err)
return
}
err = nMsg.peer.SendMessage(
false, chanAnn,
)
if err != nil {
log.Errorf("Failed sending "+
"full proof to "+
"peer=%x: %v",
peerID, err)
return
}
log.Debugf("Full proof sent to peer=%x"+
" for chanID=%v", peerID,
msg.ChannelID)
}()
}
log.Debugf("Already have proof for channel "+
"with chanID=%v", msg.ChannelID)
nMsg.err <- nil
return nil, true
}
// Check that we received the opposite proof. If so, then we're
// now able to construct the full proof, and create the channel
// announcement. If we didn't receive the opposite half of the
// proof than we should store it this one, and wait for
// opposite to be received.
proof := channeldb.NewWaitingProof(nMsg.isRemote, msg)
oppositeProof, err := d.cfg.WaitingProofStore.Get(
proof.OppositeKey(),
)
if err != nil && err != channeldb.ErrWaitingProofNotFound {
err := fmt.Errorf("unable to get "+
"the opposite proof for short_chan_id=%v: %v",
shortChanID, err)
log.Error(err)
nMsg.err <- err
return nil, false
}
if err == channeldb.ErrWaitingProofNotFound {
err := d.cfg.WaitingProofStore.Add(proof)
if err != nil {
err := fmt.Errorf("unable to store "+
"the proof for short_chan_id=%v: %v",
shortChanID, err)
log.Error(err)
nMsg.err <- err
return nil, false
}
log.Infof("1/2 of channel ann proof received for "+
"short_chan_id=%v, waiting for other half",
shortChanID)
nMsg.err <- nil
return nil, false
}
// We now have both halves of the channel announcement proof,
// then we'll reconstruct the initial announcement so we can
// validate it shortly below.
var dbProof channeldb.ChannelAuthProof
if isFirstNode {
dbProof.NodeSig1Bytes = msg.NodeSignature.ToSignatureBytes()
dbProof.NodeSig2Bytes = oppositeProof.NodeSignature.ToSignatureBytes()
dbProof.BitcoinSig1Bytes = msg.BitcoinSignature.ToSignatureBytes()
dbProof.BitcoinSig2Bytes = oppositeProof.BitcoinSignature.ToSignatureBytes()
} else {
dbProof.NodeSig1Bytes = oppositeProof.NodeSignature.ToSignatureBytes()
dbProof.NodeSig2Bytes = msg.NodeSignature.ToSignatureBytes()
dbProof.BitcoinSig1Bytes = oppositeProof.BitcoinSignature.ToSignatureBytes()
dbProof.BitcoinSig2Bytes = msg.BitcoinSignature.ToSignatureBytes()
}
chanAnn, e1Ann, e2Ann, err := netann.CreateChanAnnouncement(
&dbProof, chanInfo, e1, e2,
)
if err != nil {
log.Error(err)
nMsg.err <- err
return nil, false
}
// With all the necessary components assembled validate the
// full channel announcement proof.
if err := routing.ValidateChannelAnn(chanAnn); err != nil {
err := fmt.Errorf("channel announcement proof "+
"for short_chan_id=%v isn't valid: %v",
shortChanID, err)
log.Error(err)
nMsg.err <- err
return nil, false
}
// If the channel was returned by the router it means that
// existence of funding point and inclusion of nodes bitcoin
// keys in it already checked by the router. In this stage we
// should check that node keys are attest to the bitcoin keys
// by validating the signatures of announcement. If proof is
// valid then we'll populate the channel edge with it, so we
// can announce it on peer connect.
err = d.cfg.Router.AddProof(msg.ShortChannelID, &dbProof)
if err != nil {
err := fmt.Errorf("unable add proof to the "+
"channel chanID=%v: %v", msg.ChannelID, err)
log.Error(err)
nMsg.err <- err
return nil, false
}
err = d.cfg.WaitingProofStore.Remove(proof.OppositeKey())
if err != nil {
err := fmt.Errorf("unable remove opposite proof "+
"for the channel with chanID=%v: %v",
msg.ChannelID, err)
log.Error(err)
nMsg.err <- err
return nil, false
}
// Proof was successfully created and now can announce the
// channel to the remain network.
log.Infof("Fully valid channel proof for short_chan_id=%v "+
"constructed, adding to next ann batch",
shortChanID)
// Assemble the necessary announcements to add to the next
// broadcasting batch.
announcements = append(announcements, networkMsg{
peer: nMsg.peer,
source: nMsg.source,
msg: chanAnn,
})
if src, err := chanInfo.NodeKey1(); err == nil && e1Ann != nil {
announcements = append(announcements, networkMsg{
peer: nMsg.peer,
source: src,
msg: e1Ann,
})
}
if src, err := chanInfo.NodeKey2(); err == nil && e2Ann != nil {
announcements = append(announcements, networkMsg{
peer: nMsg.peer,
source: src,
msg: e2Ann,
})
}
// We'll also send along the node announcements for each channel
// participant if we know of them. To ensure our node
// announcement propagates to our channel counterparty, we'll
// set the source for each announcement to the node it belongs
// to, otherwise we won't send it since the source gets skipped.
// This isn't necessary for channel updates and announcement
// signatures since we send those directly to our channel
// counterparty through the gossiper's reliable sender.
node1Ann, err := d.fetchNodeAnn(chanInfo.NodeKey1Bytes)
if err != nil {
log.Debugf("Unable to fetch node announcement for "+
"%x: %v", chanInfo.NodeKey1Bytes, err)
} else {
if nodeKey1, err := chanInfo.NodeKey1(); err == nil {
announcements = append(announcements, networkMsg{
peer: nMsg.peer,
source: nodeKey1,
msg: node1Ann,
})
}
}
node2Ann, err := d.fetchNodeAnn(chanInfo.NodeKey2Bytes)
if err != nil {
log.Debugf("Unable to fetch node announcement for "+
"%x: %v", chanInfo.NodeKey2Bytes, err)
} else {
if nodeKey2, err := chanInfo.NodeKey2(); err == nil {
announcements = append(announcements, networkMsg{
peer: nMsg.peer,
source: nodeKey2,
msg: node2Ann,
})
}
}
nMsg.err <- nil
return announcements, true
default: default:
err := errors.New("wrong type of the announcement") err := errors.New("wrong type of the announcement")
@ -2978,3 +2658,309 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg,
nMsg.err <- nil nMsg.err <- nil
return announcements, true return announcements, true
} }
// handleAnnSig processes a new announcement signatures message.
func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg,
ann *lnwire.AnnounceSignatures) ([]networkMsg, bool) {
needBlockHeight := ann.ShortChannelID.BlockHeight +
d.cfg.ProofMatureDelta
shortChanID := ann.ShortChannelID.ToUint64()
prefix := "local"
if nMsg.isRemote {
prefix = "remote"
}
log.Infof("Received new %v channel announcement for %v", prefix,
ann.ShortChannelID)
// By the specification, channel announcement proofs should be sent
// after some number of confirmations after channel was registered in
// bitcoin blockchain. Therefore, we check if the proof is mature.
d.Lock()
premature := d.isPremature(
ann.ShortChannelID, d.cfg.ProofMatureDelta, nMsg,
)
if premature {
log.Warnf("Premature proof announcement, current block height"+
"lower than needed: %v < %v", d.bestHeight,
needBlockHeight)
d.Unlock()
nMsg.err <- nil
return nil, false
}
d.Unlock()
// Ensure that we know of a channel with the target channel ID before
// proceeding further.
//
// We must acquire the mutex for this channel ID before getting the
// channel from the database, to ensure what we read does not change
// before we call AddProof() later.
d.channelMtx.Lock(ann.ShortChannelID.ToUint64())
defer d.channelMtx.Unlock(ann.ShortChannelID.ToUint64())
chanInfo, e1, e2, err := d.cfg.Router.GetChannelByID(
ann.ShortChannelID,
)
if err != nil {
proof := channeldb.NewWaitingProof(nMsg.isRemote, ann)
err := d.cfg.WaitingProofStore.Add(proof)
if err != nil {
err := fmt.Errorf("unable to store the proof for "+
"short_chan_id=%v: %v", shortChanID, err)
log.Error(err)
nMsg.err <- err
return nil, false
}
log.Infof("Orphan %v proof announcement with short_chan_id=%v"+
", adding to waiting batch", prefix, shortChanID)
nMsg.err <- nil
return nil, false
}
nodeID := nMsg.source.SerializeCompressed()
isFirstNode := bytes.Equal(nodeID, chanInfo.NodeKey1Bytes[:])
isSecondNode := bytes.Equal(nodeID, chanInfo.NodeKey2Bytes[:])
// Ensure that channel that was retrieved belongs to the peer which
// sent the proof announcement.
if !(isFirstNode || isSecondNode) {
err := fmt.Errorf("channel that was received doesn't belong "+
"to the peer which sent the proof, short_chan_id=%v",
shortChanID)
log.Error(err)
nMsg.err <- err
return nil, false
}
// If proof was sent by a local sub-system, then we'll send the
// announcement signature to the remote node so they can also
// reconstruct the full channel announcement.
if !nMsg.isRemote {
var remotePubKey [33]byte
if isFirstNode {
remotePubKey = chanInfo.NodeKey2Bytes
} else {
remotePubKey = chanInfo.NodeKey1Bytes
}
// Since the remote peer might not be online we'll call a
// method that will attempt to deliver the proof when it comes
// online.
err := d.reliableSender.sendMessage(ann, remotePubKey)
if err != nil {
err := fmt.Errorf("unable to reliably send %v for "+
"channel=%v to peer=%x: %v", ann.MsgType(),
ann.ShortChannelID, remotePubKey, err)
nMsg.err <- err
return nil, false
}
}
// Check if we already have the full proof for this channel.
if chanInfo.AuthProof != nil {
// If we already have the fully assembled proof, then the peer
// sending us their proof has probably not received our local
// proof yet. So be kind and send them the full proof.
if nMsg.isRemote {
peerID := nMsg.source.SerializeCompressed()
log.Debugf("Got AnnounceSignatures for channel with " +
"full proof.")
d.wg.Add(1)
go func() {
defer d.wg.Done()
log.Debugf("Received half proof for channel "+
"%v with existing full proof. Sending"+
" full proof to peer=%x",
ann.ChannelID, peerID)
ca, _, _, err := netann.CreateChanAnnouncement(
chanInfo.AuthProof, chanInfo, e1, e2,
)
if err != nil {
log.Errorf("unable to gen ann: %v",
err)
return
}
err = nMsg.peer.SendMessage(false, ca)
if err != nil {
log.Errorf("Failed sending full proof"+
" to peer=%x: %v", peerID, err)
return
}
log.Debugf("Full proof sent to peer=%x for "+
"chanID=%v", peerID, ann.ChannelID)
}()
}
log.Debugf("Already have proof for channel with chanID=%v",
ann.ChannelID)
nMsg.err <- nil
return nil, true
}
// Check that we received the opposite proof. If so, then we're now
// able to construct the full proof, and create the channel
// announcement. If we didn't receive the opposite half of the proof
// then we should store this one, and wait for the opposite to be
// received.
proof := channeldb.NewWaitingProof(nMsg.isRemote, ann)
oppProof, err := d.cfg.WaitingProofStore.Get(proof.OppositeKey())
if err != nil && err != channeldb.ErrWaitingProofNotFound {
err := fmt.Errorf("unable to get the opposite proof for "+
"short_chan_id=%v: %v", shortChanID, err)
log.Error(err)
nMsg.err <- err
return nil, false
}
if err == channeldb.ErrWaitingProofNotFound {
err := d.cfg.WaitingProofStore.Add(proof)
if err != nil {
err := fmt.Errorf("unable to store the proof for "+
"short_chan_id=%v: %v", shortChanID, err)
log.Error(err)
nMsg.err <- err
return nil, false
}
log.Infof("1/2 of channel ann proof received for "+
"short_chan_id=%v, waiting for other half",
shortChanID)
nMsg.err <- nil
return nil, false
}
// We now have both halves of the channel announcement proof, then
// we'll reconstruct the initial announcement so we can validate it
// shortly below.
var dbProof channeldb.ChannelAuthProof
if isFirstNode {
dbProof.NodeSig1Bytes = ann.NodeSignature.ToSignatureBytes()
dbProof.NodeSig2Bytes = oppProof.NodeSignature.ToSignatureBytes()
dbProof.BitcoinSig1Bytes = ann.BitcoinSignature.ToSignatureBytes()
dbProof.BitcoinSig2Bytes = oppProof.BitcoinSignature.ToSignatureBytes()
} else {
dbProof.NodeSig1Bytes = oppProof.NodeSignature.ToSignatureBytes()
dbProof.NodeSig2Bytes = ann.NodeSignature.ToSignatureBytes()
dbProof.BitcoinSig1Bytes = oppProof.BitcoinSignature.ToSignatureBytes()
dbProof.BitcoinSig2Bytes = ann.BitcoinSignature.ToSignatureBytes()
}
chanAnn, e1Ann, e2Ann, err := netann.CreateChanAnnouncement(
&dbProof, chanInfo, e1, e2,
)
if err != nil {
log.Error(err)
nMsg.err <- err
return nil, false
}
// With all the necessary components assembled validate the full
// channel announcement proof.
if err := routing.ValidateChannelAnn(chanAnn); err != nil {
err := fmt.Errorf("channel announcement proof for "+
"short_chan_id=%v isn't valid: %v", shortChanID, err)
log.Error(err)
nMsg.err <- err
return nil, false
}
// If the channel was returned by the router it means that existence of
// funding point and inclusion of nodes bitcoin keys in it already
// checked by the router. In this stage we should check that node keys
// attest to the bitcoin keys by validating the signatures of
// announcement. If proof is valid then we'll populate the channel edge
// with it, so we can announce it on peer connect.
err = d.cfg.Router.AddProof(ann.ShortChannelID, &dbProof)
if err != nil {
err := fmt.Errorf("unable add proof to the channel chanID=%v:"+
" %v", ann.ChannelID, err)
log.Error(err)
nMsg.err <- err
return nil, false
}
err = d.cfg.WaitingProofStore.Remove(proof.OppositeKey())
if err != nil {
err := fmt.Errorf("unable to remove opposite proof for the "+
"channel with chanID=%v: %v", ann.ChannelID, err)
log.Error(err)
nMsg.err <- err
return nil, false
}
// Proof was successfully created and now can announce the channel to
// the remain network.
log.Infof("Fully valid channel proof for short_chan_id=%v constructed"+
", adding to next ann batch", shortChanID)
// Assemble the necessary announcements to add to the next broadcasting
// batch.
var announcements []networkMsg
announcements = append(announcements, networkMsg{
peer: nMsg.peer,
source: nMsg.source,
msg: chanAnn,
})
if src, err := chanInfo.NodeKey1(); err == nil && e1Ann != nil {
announcements = append(announcements, networkMsg{
peer: nMsg.peer,
source: src,
msg: e1Ann,
})
}
if src, err := chanInfo.NodeKey2(); err == nil && e2Ann != nil {
announcements = append(announcements, networkMsg{
peer: nMsg.peer,
source: src,
msg: e2Ann,
})
}
// We'll also send along the node announcements for each channel
// participant if we know of them. To ensure our node announcement
// propagates to our channel counterparty, we'll set the source for
// each announcement to the node it belongs to, otherwise we won't send
// it since the source gets skipped. This isn't necessary for channel
// updates and announcement signatures since we send those directly to
// our channel counterparty through the gossiper's reliable sender.
node1Ann, err := d.fetchNodeAnn(chanInfo.NodeKey1Bytes)
if err != nil {
log.Debugf("Unable to fetch node announcement for %x: %v",
chanInfo.NodeKey1Bytes, err)
} else {
if nodeKey1, err := chanInfo.NodeKey1(); err == nil {
announcements = append(announcements, networkMsg{
peer: nMsg.peer,
source: nodeKey1,
msg: node1Ann,
})
}
}
node2Ann, err := d.fetchNodeAnn(chanInfo.NodeKey2Bytes)
if err != nil {
log.Debugf("Unable to fetch node announcement for %x: %v",
chanInfo.NodeKey2Bytes, err)
} else {
if nodeKey2, err := chanInfo.NodeKey2(); err == nil {
announcements = append(announcements, networkMsg{
peer: nMsg.peer,
source: nodeKey2,
msg: node2Ann,
})
}
}
nMsg.err <- nil
return announcements, true
}