Skip to content

Commit a776c94

Browse files
committed
discovery: send signature announcement once
This change aligns our behavior with latest protocol guidelines. That is, when we receive a signature announcement when we already have the full proof we reply with our signature announcement once per (re)connection. see: lightning/bolts#1256
1 parent 4815052 commit a776c94

File tree

3 files changed

+119
-7
lines changed

3 files changed

+119
-7
lines changed

discovery/gossiper.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3489,6 +3489,30 @@ func (d *AuthenticatedGossiper) handleAnnSig(ctx context.Context,
34893489
peerID := nMsg.source.SerializeCompressed()
34903490
log.Debugf("Got AnnounceSignatures for channel with " +
34913491
"full proof.")
3492+
syncer, ok := d.syncMgr.GossipSyncer(
3493+
route.Vertex(peerID),
3494+
)
3495+
if !ok {
3496+
log.Errorf("Failed to get gossip syncer for "+
3497+
"peer=%x", peerID)
3498+
return nil, false
3499+
}
3500+
3501+
// If we already sent our proof to this peer once since
3502+
// (re)connecting, then we can skip sending it again.
3503+
syncer.Lock()
3504+
alreadySent := syncer.proofSentToChan.Contains(
3505+
ann.ChannelID,
3506+
)
3507+
syncer.Unlock()
3508+
if alreadySent {
3509+
log.Debugf("Skipping sending announcement " +
3510+
"signatures since we already did " +
3511+
"during this connection.")
3512+
nMsg.err <- nil
3513+
3514+
return nil, true
3515+
}
34923516

34933517
d.wg.Add(1)
34943518
go func() {
@@ -3529,6 +3553,10 @@ func (d *AuthenticatedGossiper) handleAnnSig(ctx context.Context,
35293553
return
35303554
}
35313555

3556+
syncer.Lock()
3557+
syncer.proofSentToChan.Add(ann.ChannelID)
3558+
syncer.Unlock()
3559+
35323560
log.Debugf("Full proof sent to peer=%x for "+
35333561
"chanID=%v", peerID, ann.ChannelID)
35343562
}()

discovery/gossiper_test.go

Lines changed: 83 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1774,16 +1774,23 @@ out:
17741774
}
17751775
}
17761776

1777-
// TestSignatureAnnouncementFullProofWhenRemoteProof tests that if a remote
1777+
// TestSignatureAnnouncementResendWhenRemoteProof tests that if a remote
17781778
// proof is received when we already have the full proof, the gossiper will send
1779-
// the full proof (ChannelAnnouncement) to the remote peer.
1780-
func TestSignatureAnnouncementFullProofWhenRemoteProof(t *testing.T) {
1779+
// our signature announcement max once per connection to the remote peer.
1780+
func TestSignatureAnnouncementResendWhenRemoteProof(t *testing.T) {
17811781
t.Parallel()
17821782
ctx := context.Background()
17831783

17841784
tCtx, err := createTestCtx(t, proofMatureDelta, false)
17851785
require.NoError(t, err, "can't create context")
17861786

1787+
// We'll create our test sync manager to have one active syncer.
1788+
syncMgr := newTestSyncManager(1)
1789+
syncMgr.Start()
1790+
defer syncMgr.Stop()
1791+
1792+
tCtx.gossiper.syncMgr = syncMgr
1793+
17871794
batch, err := tCtx.createLocalAnnouncements(0)
17881795
require.NoError(t, err, "can't generate announcements")
17891796

@@ -1797,8 +1804,16 @@ func TestSignatureAnnouncementFullProofWhenRemoteProof(t *testing.T) {
17971804
remoteKey, sentToPeer, tCtx.gossiper.quit, atomic.Bool{},
17981805
}
17991806

1807+
// We create an active syncer for our remote peer.
1808+
err = syncMgr.InitSyncState(remotePeer)
1809+
require.NoError(t, err, "failed to init sync state")
1810+
remoteSyncer := assertSyncerExistence(t, syncMgr, remotePeer)
1811+
assertTransitionToChansSynced(t, remoteSyncer, remotePeer)
1812+
assertActiveGossipTimestampRange(t, remotePeer)
1813+
assertSyncerStatus(t, remoteSyncer, chansSynced, ActiveSync)
1814+
18001815
// Override NotifyWhenOnline to return the remote peer which we expect
1801-
// meesages to be sent to.
1816+
// messages to be sent to.
18021817
tCtx.gossiper.reliableSender.cfg.NotifyWhenOnline = func(_ [33]byte,
18031818
peerChan chan<- lnpeer.Peer) {
18041819

@@ -1940,7 +1955,68 @@ func TestSignatureAnnouncementFullProofWhenRemoteProof(t *testing.T) {
19401955
}
19411956

19421957
// Now give the gossiper the remote proof yet again. This should
1943-
// trigger a send of the full ChannelAnnouncement.
1958+
// trigger a send of our signature announcement.
1959+
select {
1960+
case err = <-tCtx.gossiper.ProcessRemoteAnnouncement(
1961+
ctx, batch.remoteProofAnn, remotePeer,
1962+
):
1963+
case <-time.After(2 * time.Second):
1964+
t.Fatal("did not process local announcement")
1965+
}
1966+
require.NoError(t, err, "unable to process remote proof")
1967+
1968+
// We expect the gossiper to send this message to the remote peer.
1969+
select {
1970+
case msg := <-sentToPeer:
1971+
_, ok := msg.(*lnwire.AnnounceSignatures1)
1972+
if !ok {
1973+
t.Fatalf("expected AnnounceSignatures1, instead got "+
1974+
"%T", msg)
1975+
}
1976+
case <-time.After(2 * time.Second):
1977+
t.Fatal("did not send local proof to peer")
1978+
}
1979+
1980+
// Now give the gossiper the remote proof a 2nd time. This should _not_
1981+
// trigger a send of our signature announcement, since we already sent
1982+
// it once and we only send it once per connection.
1983+
select {
1984+
case err = <-tCtx.gossiper.ProcessRemoteAnnouncement(
1985+
ctx, batch.remoteProofAnn, remotePeer,
1986+
):
1987+
case <-time.After(2 * time.Second):
1988+
t.Fatal("did not process local announcement")
1989+
}
1990+
require.NoError(t, err, "unable to process remote proof")
1991+
1992+
// We expect the gossiper to _not_ send this message to the remote peer.
1993+
select {
1994+
case msg := <-sentToPeer:
1995+
_, ok := msg.(*lnwire.AnnounceSignatures1)
1996+
if ok {
1997+
t.Fatalf("got an AnnounceSignatures1 when none was "+
1998+
"expected %T", msg)
1999+
}
2000+
case <-time.After(2 * time.Second):
2001+
break
2002+
}
2003+
2004+
// We prune the syncer, simulating the remote peer having disconnected.
2005+
syncMgr.PruneSyncState(remotePeer.PubKey())
2006+
2007+
// We simulate the remote peer coming back online.
2008+
err = syncMgr.InitSyncState(remotePeer)
2009+
require.NoError(t, err, "failed to init sync state")
2010+
remoteSyncer1 := assertSyncerExistence(t, syncMgr, remotePeer)
2011+
assertTransitionToChansSynced(t, remoteSyncer1, remotePeer)
2012+
assertActiveGossipTimestampRange(t, remotePeer)
2013+
assertSyncerStatus(t, remoteSyncer1, chansSynced, ActiveSync)
2014+
2015+
// Now give the gossiper the remote proof a 3rd time. This should
2016+
// trigger a send of our signature announcement, since the syncer
2017+
// was pruned and we now have a new syncer for the remote peer.
2018+
// This is to simulate the case where the remote peer disconnects and
2019+
// reconnects, and we have to send the signature announcement again.
19442020
select {
19452021
case err = <-tCtx.gossiper.ProcessRemoteAnnouncement(
19462022
ctx, batch.remoteProofAnn, remotePeer,
@@ -1953,9 +2029,9 @@ func TestSignatureAnnouncementFullProofWhenRemoteProof(t *testing.T) {
19532029
// We expect the gossiper to send this message to the remote peer.
19542030
select {
19552031
case msg := <-sentToPeer:
1956-
_, ok := msg.(*lnwire.ChannelAnnouncement1)
2032+
_, ok := msg.(*lnwire.AnnounceSignatures1)
19572033
if !ok {
1958-
t.Fatalf("expected ChannelAnnouncement1, instead got "+
2034+
t.Fatalf("expected AnnounceSignatures1, instead got "+
19592035
"%T", msg)
19602036
}
19612037
case <-time.After(2 * time.Second):

discovery/syncer.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,13 @@ type GossipSyncer struct {
371371
// state.
372372
newChansToQuery []lnwire.ShortChannelID
373373

374+
// proofSentToChan is used when we already have the fully assembled
375+
// proof for a channel and the peer sending us their proof has probably
376+
// not received our local proof yet. So we are kind and send them our
377+
// proof, but only if we haven't done so since (re)connecting. We keep
378+
// track of sends with this map, so we don't send it twice.
379+
proofSentToChan fn.Set[lnwire.ChannelID]
380+
374381
cfg gossipSyncerCfg
375382

376383
// syncedSignal is a channel that, if set, will be closed when the
@@ -399,6 +406,7 @@ func newGossipSyncer(cfg gossipSyncerCfg, sema chan struct{}) *GossipSyncer {
399406
gossipMsgs: make(chan lnwire.Message, syncerBufferSize),
400407
queryMsgs: make(chan lnwire.Message, syncerBufferSize),
401408
syncerSema: sema,
409+
proofSentToChan: fn.NewSet[lnwire.ChannelID](),
402410
cg: fn.NewContextGuard(),
403411
}
404412
}

0 commit comments

Comments
 (0)