discovery: fix silent remote orphan announcement proof rejection

In case of the situation when we receive remote announcement with
channel id which pointing out to unknown channel the announcement have
been silently rejected. Now such announcement will be added to the
waiting proof map.

Such solution has a serious drawback - by adding the announcement proof
without information about channel itself (that this announcement have
been received from the node eligible to sending it), we allow
overwriting the waiting proof map by `Eve` node.
This commit is contained in:
Andrey Samokhvalov 2017-04-26 05:04:53 +03:00 committed by Olaoluwa Osuntokun
parent 0779ce59fe
commit 337a4a4f56
2 changed files with 100 additions and 10 deletions

@ -226,7 +226,7 @@ func (d *AuthenticatedGossiper) ProcessRemoteAnnouncement(msg lnwire.Message,
select {
case d.networkMsgs <- nMsg:
case <-d.quit:
nMsg.err <- errors.New("discovery has shut down")
nMsg.err <- errors.New("gossiper has shut down")
}
return nMsg.err
@ -252,7 +252,7 @@ func (d *AuthenticatedGossiper) ProcessLocalAnnouncement(msg lnwire.Message,
select {
case d.networkMsgs <- nMsg:
case <-d.quit:
nMsg.err <- errors.New("discovery has shut down")
nMsg.err <- errors.New("gossiper has shut down")
}
return nMsg.err
@ -589,6 +589,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []l
err := errors.Errorf("unable to validate "+
"channel update short_chan_id=%v: %v",
shortChanID, err)
log.Error(err)
nMsg.err <- err
return nil
}
@ -686,10 +687,15 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []l
// before proceeding further.
chanInfo, e1, e2, err := d.cfg.Router.GetChannelByID(msg.ShortChannelID)
if err != nil {
err := errors.Errorf("unable to process channel "+
"%v proof with short_chan_id=%v: %v", prefix,
shortChanID, err)
nMsg.err <- err
// TODO(andrew.shvv) this is dangerous because remote
// node might rewrite the waiting proof.
key := newProofKey(shortChanID, nMsg.isRemote)
d.waitingProofs[key] = msg
log.Infof("Orphan %v proof announcement with "+
"short_chan_id=%v, adding"+
"to waiting batch", prefix, shortChanID)
nMsg.err <- nil
return nil
}
@ -799,6 +805,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(nMsg *networkMsg) []l
nMsg.err <- err
return nil
}
delete(d.waitingProofs, oppositeKey)
// Proof was successfully created and now can announce the
// channel to the remain network.

@ -51,7 +51,7 @@ var (
nodeKeyPriv2, _ = btcec.NewPrivateKey(btcec.S256())
nodeKeyPub2 = nodeKeyPriv2.PubKey()
trickleDelay = time.Millisecond * 300
trickleDelay = time.Millisecond * 100
proofMatureDelta uint32
)
@ -577,10 +577,10 @@ func TestPrematureAnnouncement(t *testing.T) {
}
}
// TestSignatureAnnouncement ensures that the AuthenticatedGossiper properly
// TestSignatureAnnouncementLocalFirst ensures that the AuthenticatedGossiper properly
// processes partial and fully announcement signatures message.
func TestSignatureAnnouncement(t *testing.T) {
ctx, cleanup, err := createTestCtx(proofMatureDelta)
func TestSignatureAnnouncementLocalFirst(t *testing.T) {
ctx, cleanup, err := createTestCtx(uint32(proofMatureDelta))
if err != nil {
t.Fatalf("can't create context: %v", err)
}
@ -656,3 +656,86 @@ func TestSignatureAnnouncement(t *testing.T) {
}
}
}
// TestOrphanSignatureAnnouncement ensures that the gossiper properly
// processes announcement with unknown channel ids.
func TestOrphanSignatureAnnouncement(t *testing.T) {
ctx, cleanup, err := createTestCtx(uint32(proofMatureDelta))
if err != nil {
t.Fatalf("can't create context: %v", err)
}
defer cleanup()
batch, err := createAnnouncements(0)
if err != nil {
t.Fatalf("can't generate announcements: %v", err)
}
localKey := batch.nodeAnn1.NodeID
remoteKey := batch.nodeAnn2.NodeID
// Pretending that we receive local channel announcement from funding
// manager, thereby kick off the announcement exchange process, in
// this case the announcement should be added in the orphan batch
// because we haven't announce the channel yet.
err = <-ctx.discovery.ProcessRemoteAnnouncement(batch.remoteProofAnn, remoteKey)
if err != nil {
t.Fatalf("unable to proceed announcement: %v", err)
}
if len(ctx.discovery.waitingProofs) != 1 {
t.Fatal("local proof announcement should be stored")
}
// Recreate lightning network topology. Initialize router with channel
// between two nodes.
err = <-ctx.discovery.ProcessLocalAnnouncement(batch.localChanAnn, localKey)
if err != nil {
t.Fatalf("unable to process :%v", err)
}
select {
case <-ctx.broadcastedMessage:
t.Fatal("channel announcement was broadcast")
case <-time.After(2 * trickleDelay):
}
err = <-ctx.discovery.ProcessLocalAnnouncement(batch.chanUpdAnn, localKey)
if err != nil {
t.Fatalf("unable to process :%v", err)
}
select {
case <-ctx.broadcastedMessage:
t.Fatal("channel update announcement was broadcast")
case <-time.After(2 * trickleDelay):
}
err = <-ctx.discovery.ProcessRemoteAnnouncement(batch.chanUpdAnn, remoteKey)
if err != nil {
t.Fatalf("unable to process :%v", err)
}
select {
case <-ctx.broadcastedMessage:
t.Fatal("channel update announcement was broadcast")
case <-time.After(2 * trickleDelay):
}
// After that we process local announcement, and waiting to receive
// the channel announcement.
err = <-ctx.discovery.ProcessLocalAnnouncement(batch.localProofAnn, localKey)
if err != nil {
t.Fatalf("unable to process :%v", err)
}
for i := 0; i < 3; i++ {
select {
case <-ctx.broadcastedMessage:
case <-time.After(time.Second):
t.Fatal("announcement wasn't broadcast")
}
}
if len(ctx.discovery.waitingProofs) != 0 {
t.Fatal("index should be removed")
}
}