Merge pull request #9595 from yyforyongyu/fix-gossip-syncer
multi: fix flakes and gossip syncer
This commit is contained in:
6 files changed
+41
-39
No files matched your search
+11
-8
@@ -571,15 +571,11 @@ func (g *GossipSyncer) channelGraphSyncer() {
|
|||||||
// First, we'll attempt to continue our channel
|
// First, we'll attempt to continue our channel
|
||||||
// synchronization by continuing to send off another
|
// synchronization by continuing to send off another
|
||||||
// query chunk.
|
// query chunk.
|
||||||
done, err := g.synchronizeChanIDs()
|
done := g.synchronizeChanIDs()
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Unable to sync chan IDs: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this wasn't our last query, then we'll need to
|
// If this wasn't our last query, then we'll need to
|
||||||
// transition to our waiting state.
|
// transition to our waiting state.
|
||||||
if !done {
|
if !done {
|
||||||
g.setSyncState(waitingQueryChanReply)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -736,14 +732,15 @@ func (g *GossipSyncer) sendGossipTimestampRange(firstTimestamp time.Time,
|
|||||||
// been queried for with a response received. We'll chunk our requests as
|
// been queried for with a response received. We'll chunk our requests as
|
||||||
// required to ensure they fit into a single message. We may re-renter this
|
// required to ensure they fit into a single message. We may re-renter this
|
||||||
// state in the case that chunking is required.
|
// state in the case that chunking is required.
|
||||||
func (g *GossipSyncer) synchronizeChanIDs() (bool, error) {
|
func (g *GossipSyncer) synchronizeChanIDs() bool {
|
||||||
// If we're in this state yet there are no more new channels to query
|
// If we're in this state yet there are no more new channels to query
|
||||||
// for, then we'll transition to our final synced state and return true
|
// for, then we'll transition to our final synced state and return true
|
||||||
// to signal that we're fully synchronized.
|
// to signal that we're fully synchronized.
|
||||||
if len(g.newChansToQuery) == 0 {
|
if len(g.newChansToQuery) == 0 {
|
||||||
log.Infof("GossipSyncer(%x): no more chans to query",
|
log.Infof("GossipSyncer(%x): no more chans to query",
|
||||||
g.cfg.peerPub[:])
|
g.cfg.peerPub[:])
|
||||||
return true, nil
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we'll issue our next chunked query to receive replies
|
// Otherwise, we'll issue our next chunked query to receive replies
|
||||||
@@ -767,6 +764,9 @@ func (g *GossipSyncer) synchronizeChanIDs() (bool, error) {
|
|||||||
log.Infof("GossipSyncer(%x): querying for %v new channels",
|
log.Infof("GossipSyncer(%x): querying for %v new channels",
|
||||||
g.cfg.peerPub[:], len(queryChunk))
|
g.cfg.peerPub[:], len(queryChunk))
|
||||||
|
|
||||||
|
// Change the state before sending the query msg.
|
||||||
|
g.setSyncState(waitingQueryChanReply)
|
||||||
|
|
||||||
// With our chunk obtained, we'll send over our next query, then return
|
// With our chunk obtained, we'll send over our next query, then return
|
||||||
// false indicating that we're net yet fully synced.
|
// false indicating that we're net yet fully synced.
|
||||||
err := g.cfg.sendToPeer(&lnwire.QueryShortChanIDs{
|
err := g.cfg.sendToPeer(&lnwire.QueryShortChanIDs{
|
||||||
@@ -774,8 +774,11 @@ func (g *GossipSyncer) synchronizeChanIDs() (bool, error) {
|
|||||||
EncodingType: lnwire.EncodingSortedPlain,
|
EncodingType: lnwire.EncodingSortedPlain,
|
||||||
ShortChanIDs: queryChunk,
|
ShortChanIDs: queryChunk,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Unable to sync chan IDs: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return false, err
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// isLegacyReplyChannelRange determines where a ReplyChannelRange message is
|
// isLegacyReplyChannelRange determines where a ReplyChannelRange message is
|
||||||
|
|||||||
@@ -1478,10 +1478,7 @@ func TestGossipSyncerSynchronizeChanIDs(t *testing.T) {
|
|||||||
|
|
||||||
for i := 0; i < chunkSize*2; i += 2 {
|
for i := 0; i < chunkSize*2; i += 2 {
|
||||||
// With our set up complete, we'll request a sync of chan ID's.
|
// With our set up complete, we'll request a sync of chan ID's.
|
||||||
done, err := syncer.synchronizeChanIDs()
|
done := syncer.synchronizeChanIDs()
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to sync chan IDs: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point, we shouldn't yet be done as only 2 items
|
// At this point, we shouldn't yet be done as only 2 items
|
||||||
// should have been queried for.
|
// should have been queried for.
|
||||||
@@ -1528,8 +1525,7 @@ func TestGossipSyncerSynchronizeChanIDs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we issue another query, the syncer should tell us that it's done.
|
// If we issue another query, the syncer should tell us that it's done.
|
||||||
done, err := syncer.synchronizeChanIDs()
|
done := syncer.synchronizeChanIDs()
|
||||||
require.NoError(t, err, "unable to sync chan IDs")
|
|
||||||
if done {
|
if done {
|
||||||
t.Fatalf("syncer should be finished!")
|
t.Fatalf("syncer should be finished!")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,9 @@
|
|||||||
could lead to our ChannelUpdate rate limiting logic being prematurely
|
could lead to our ChannelUpdate rate limiting logic being prematurely
|
||||||
triggered.
|
triggered.
|
||||||
|
|
||||||
|
* [Fixed a bug](https://github.com/lightningnetwork/lnd/pull/9595) where the
|
||||||
|
initial graph sync query may be failed due to inconsistent state.
|
||||||
|
|
||||||
# New Features
|
# New Features
|
||||||
|
|
||||||
* [Support](https://github.com/lightningnetwork/lnd/pull/8390) for
|
* [Support](https://github.com/lightningnetwork/lnd/pull/8390) for
|
||||||
|
|||||||
@@ -438,12 +438,6 @@ func testForwardInterceptorRestart(ht *lntest.HarnessTest) {
|
|||||||
require.Equal(ht, lntest.CustomRecordsWithUnendorsed(customRecords),
|
require.Equal(ht, lntest.CustomRecordsWithUnendorsed(customRecords),
|
||||||
packet.InWireCustomRecords)
|
packet.InWireCustomRecords)
|
||||||
|
|
||||||
err = carolInterceptor.Send(&routerrpc.ForwardHtlcInterceptResponse{
|
|
||||||
IncomingCircuitKey: packet.IncomingCircuitKey,
|
|
||||||
Action: actionResume,
|
|
||||||
})
|
|
||||||
require.NoError(ht, err, "failed to send request")
|
|
||||||
|
|
||||||
// And now we forward the payment at Carol, expecting only an
|
// And now we forward the payment at Carol, expecting only an
|
||||||
// endorsement signal in our incoming custom records.
|
// endorsement signal in our incoming custom records.
|
||||||
packet = ht.ReceiveHtlcInterceptor(carolInterceptor)
|
packet = ht.ReceiveHtlcInterceptor(carolInterceptor)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
|
"github.com/lightningnetwork/lnd/lnutils"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
@@ -60,6 +61,9 @@ func (r *forwardInterceptor) run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Tracef("Received packet from stream: %v",
|
||||||
|
lnutils.SpewLogClosure(resp))
|
||||||
|
|
||||||
if err := r.resolveFromClient(resp); err != nil {
|
if err := r.resolveFromClient(resp); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -73,7 +77,8 @@ func (r *forwardInterceptor) run() error {
|
|||||||
func (r *forwardInterceptor) onIntercept(
|
func (r *forwardInterceptor) onIntercept(
|
||||||
htlc htlcswitch.InterceptedPacket) error {
|
htlc htlcswitch.InterceptedPacket) error {
|
||||||
|
|
||||||
log.Tracef("Sending intercepted packet to client %v", htlc)
|
log.Tracef("Sending intercepted packet to client %v",
|
||||||
|
lnutils.SpewLogClosure(htlc))
|
||||||
|
|
||||||
inKey := htlc.IncomingCircuit
|
inKey := htlc.IncomingCircuit
|
||||||
|
|
||||||
|
|||||||
+19
-18
@@ -319,14 +319,20 @@ func TestReconnectSucceed(t *testing.T) {
|
|||||||
// Close the old conn before reconnection.
|
// Close the old conn before reconnection.
|
||||||
require.NoError(t, proxy.serverConn.Close())
|
require.NoError(t, proxy.serverConn.Close())
|
||||||
|
|
||||||
// Accept the connection inside a goroutine. We will also write some
|
// Accept the connection inside a goroutine. When the client makes a
|
||||||
// data so that the reconnection can succeed. We will mock three writes
|
// reconnection, the messages flow is,
|
||||||
// and two reads inside our proxy server,
|
// 1. the client sends the command PROTOCOLINFO to the server.
|
||||||
// - write protocol info
|
// 2. the server responds with its protocol version.
|
||||||
// - read auth info
|
// 3. the client reads the response and sends the command AUTHENTICATE
|
||||||
// - write auth challenge
|
// to the server
|
||||||
// - read auth challenge
|
// 4. the server responds with the authentication info.
|
||||||
// - write OK
|
//
|
||||||
|
// From the server's PoV, We need to mock two reads and two writes
|
||||||
|
// inside the connection,
|
||||||
|
// 1. read the command PROTOCOLINFO sent from the client.
|
||||||
|
// 2. write protocol info so the client can read it.
|
||||||
|
// 3. read the command AUTHENTICATE sent from the client.
|
||||||
|
// 4. write auth challenge so the client can read it.
|
||||||
go func() {
|
go func() {
|
||||||
// Accept the new connection.
|
// Accept the new connection.
|
||||||
server, err := proxy.server.Accept()
|
server, err := proxy.server.Accept()
|
||||||
@@ -335,6 +341,11 @@ func TestReconnectSucceed(t *testing.T) {
|
|||||||
t.Logf("server listening on %v, client listening on %v",
|
t.Logf("server listening on %v, client listening on %v",
|
||||||
server.LocalAddr(), server.RemoteAddr())
|
server.LocalAddr(), server.RemoteAddr())
|
||||||
|
|
||||||
|
// Read the protocol command from the client.
|
||||||
|
buf := make([]byte, 65535)
|
||||||
|
_, err = server.Read(buf)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Write the protocol info.
|
// Write the protocol info.
|
||||||
resp := "250-PROTOCOLINFO 1\n" +
|
resp := "250-PROTOCOLINFO 1\n" +
|
||||||
"250-AUTH METHODS=NULL\n" +
|
"250-AUTH METHODS=NULL\n" +
|
||||||
@@ -343,7 +354,6 @@ func TestReconnectSucceed(t *testing.T) {
|
|||||||
require.NoErrorf(t, err, "failed to write protocol info")
|
require.NoErrorf(t, err, "failed to write protocol info")
|
||||||
|
|
||||||
// Read the auth info from the client.
|
// Read the auth info from the client.
|
||||||
buf := make([]byte, 65535)
|
|
||||||
_, err = server.Read(buf)
|
_, err = server.Read(buf)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -351,15 +361,6 @@ func TestReconnectSucceed(t *testing.T) {
|
|||||||
resp = "250 AUTHCHALLENGE SERVERHASH=fake\n"
|
resp = "250 AUTHCHALLENGE SERVERHASH=fake\n"
|
||||||
_, err = server.Write([]byte(resp))
|
_, err = server.Write([]byte(resp))
|
||||||
require.NoErrorf(t, err, "failed to write auth challenge")
|
require.NoErrorf(t, err, "failed to write auth challenge")
|
||||||
|
|
||||||
// Read the auth challenge resp from the client.
|
|
||||||
_, err = server.Read(buf)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Write OK resp.
|
|
||||||
resp = "250 OK\n"
|
|
||||||
_, err = server.Write([]byte(resp))
|
|
||||||
require.NoErrorf(t, err, "failed to write response auth")
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Reconnect should succeed.
|
// Reconnect should succeed.
|
||||||
|
|||||||
Reference in new issue
Block a user