Skip to content

Commit 51f3577

Browse files
authored
Merge pull request #8963 from Roasbeef/always-send-chan-upd
peer: always send channel update on reconnect
2 parents 459ee9b + 9acad37 commit 51f3577

File tree

4 files changed

+131
-2
lines changed

4 files changed

+131
-2
lines changed

docs/release-notes/release-notes-0.18.3.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ commitment when the channel was force closed.
5757
[here](https://github.com/lightningnetwork/lnd/issues/8146) for a summary of
5858
the issue.
5959

60+
* We'll now always send [channel updates to our remote peer for open
61+
channels](https://github.com/lightningnetwork/lnd/pull/8963).
62+
6063
# New Features
6164
## Functional Enhancements
6265
## RPC Additions
@@ -247,6 +250,7 @@ commitment when the channel was force closed.
247250
* Elle Mouton
248251
* Eugene Siegel
249252
* Matheus Degiovani
253+
* Olaoluwa Osuntokun
250254
* Oliver Gugger
251255
* Slyghtning
252256
* Yong Yu

peer/brontide.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,9 @@ func (p *Brontide) Start() error {
787787
//
788788
// TODO(wilmer): Remove this once we're able to query for node
789789
// announcements through their timestamps.
790+
p.wg.Add(2)
790791
go p.maybeSendNodeAnn(activeChans)
792+
go p.maybeSendChannelUpdates()
791793

792794
return nil
793795
}
@@ -1218,6 +1220,8 @@ func (p *Brontide) addLink(chanPoint *wire.OutPoint,
12181220
// maybeSendNodeAnn sends our node announcement to the remote peer if at least
12191221
// one confirmed public channel exists with them.
12201222
func (p *Brontide) maybeSendNodeAnn(channels []*channeldb.OpenChannel) {
1223+
defer p.wg.Done()
1224+
12211225
hasConfirmedPublicChan := false
12221226
for _, channel := range channels {
12231227
if channel.IsPending {
@@ -1245,6 +1249,72 @@ func (p *Brontide) maybeSendNodeAnn(channels []*channeldb.OpenChannel) {
12451249
}
12461250
}
12471251

1252+
// maybeSendChannelUpdates sends our channel updates to the remote peer if we
1253+
// have any active channels with them.
1254+
func (p *Brontide) maybeSendChannelUpdates() {
1255+
defer p.wg.Done()
1256+
1257+
// If we don't have any active channels, then we can exit early.
1258+
if p.activeChannels.Len() == 0 {
1259+
return
1260+
}
1261+
1262+
maybeSendUpd := func(cid lnwire.ChannelID,
1263+
lnChan *lnwallet.LightningChannel) error {
1264+
1265+
// Nil channels are pending, so we'll skip them.
1266+
if lnChan == nil {
1267+
return nil
1268+
}
1269+
1270+
dbChan := lnChan.State()
1271+
scid := func() lnwire.ShortChannelID {
1272+
switch {
1273+
// Otherwise if it's a zero conf channel and confirmed,
1274+
// then we need to use the "real" scid.
1275+
case dbChan.IsZeroConf() && dbChan.ZeroConfConfirmed():
1276+
return dbChan.ZeroConfRealScid()
1277+
1278+
// Otherwise, we can use the normal scid.
1279+
default:
1280+
return dbChan.ShortChanID()
1281+
}
1282+
}()
1283+
1284+
// Now that we know the channel is in a good state, we'll try
1285+
// to fetch the update to send to the remote peer. If the
1286+
// channel is pending, and not a zero conf channel, we'll get
1287+
// an error here which we'll ignore.
1288+
chanUpd, err := p.cfg.FetchLastChanUpdate(scid)
1289+
if err != nil {
1290+
p.log.Debugf("Unable to fetch channel update for "+
1291+
"ChannelPoint(%v), scid=%v: %v",
1292+
dbChan.FundingOutpoint, dbChan.ShortChanID, err)
1293+
1294+
return nil
1295+
}
1296+
1297+
p.log.Debugf("Sending channel update for ChannelPoint(%v), "+
1298+
"scid=%v", dbChan.FundingOutpoint, dbChan.ShortChanID)
1299+
1300+
// We'll send it as a normal message instead of using the lazy
1301+
// queue to prioritize transmission of the fresh update.
1302+
if err := p.SendMessage(false, chanUpd); err != nil {
1303+
err := fmt.Errorf("unable to send channel update for "+
1304+
"ChannelPoint(%v), scid=%v: %w",
1305+
dbChan.FundingOutpoint, dbChan.ShortChanID(),
1306+
err)
1307+
p.log.Errorf(err.Error())
1308+
1309+
return err
1310+
}
1311+
1312+
return nil
1313+
}
1314+
1315+
p.activeChannels.ForEach(maybeSendUpd)
1316+
}
1317+
12481318
// WaitForDisconnect waits until the peer has disconnected. A peer may be
12491319
// disconnected if the local or remote side terminates the connection, or an
12501320
// irrecoverable protocol error has been encountered. This method will only

peer/brontide_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,6 +1100,51 @@ func TestUpdateNextRevocation(t *testing.T) {
11001100
// `lnwallet.LightningWallet` once it's interfaced.
11011101
}
11021102

1103+
func assertMsgSent(t *testing.T, conn *mockMessageConn,
1104+
msgType lnwire.MessageType) {
1105+
1106+
t.Helper()
1107+
1108+
require := require.New(t)
1109+
1110+
rawMsg, err := fn.RecvOrTimeout(conn.writtenMessages, timeout)
1111+
require.NoError(err)
1112+
1113+
msgReader := bytes.NewReader(rawMsg)
1114+
msg, err := lnwire.ReadMessage(msgReader, 0)
1115+
require.NoError(err)
1116+
1117+
require.Equal(msgType, msg.MsgType())
1118+
}
1119+
1120+
// TestAlwaysSendChannelUpdate tests that each time we connect to the peer if
1121+
// an active channel, we always send the latest channel update.
1122+
func TestAlwaysSendChannelUpdate(t *testing.T) {
1123+
require := require.New(t)
1124+
1125+
var channel *channeldb.OpenChannel
1126+
channelIntercept := func(a, b *channeldb.OpenChannel) {
1127+
channel = a
1128+
}
1129+
1130+
harness, err := createTestPeerWithChannel(t, channelIntercept)
1131+
require.NoError(err, "unable to create test channels")
1132+
1133+
// Avoid the need to mock the channel graph by marking the channel
1134+
// borked. Borked channels still get a reestablish message sent on
1135+
// reconnect, while skipping channel graph checks and link creation.
1136+
require.NoError(channel.MarkBorked())
1137+
1138+
// Start the peer, which'll trigger the normal init and start up logic.
1139+
startPeerDone := startPeer(t, harness.mockConn, harness.peer)
1140+
_, err = fn.RecvOrTimeout(startPeerDone, 2*timeout)
1141+
require.NoError(err)
1142+
1143+
// Assert that we eventually send a channel update.
1144+
assertMsgSent(t, harness.mockConn, lnwire.MsgChannelReestablish)
1145+
assertMsgSent(t, harness.mockConn, lnwire.MsgChannelUpdate)
1146+
}
1147+
11031148
// TODO(yy): add test for `addActiveChannel` and `handleNewActiveChannel` once
11041149
// we have interfaced `lnwallet.LightningChannel` and
11051150
// `*contractcourt.ChainArbitrator`.

peer/test_utils.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ func createTestPeerWithChannel(t *testing.T, updateChan func(a,
341341
notifier: notifier,
342342
publishTx: publishTx,
343343
mockSwitch: mockSwitch,
344+
mockConn: params.mockConn,
344345
}, nil
345346
}
346347

@@ -493,10 +494,14 @@ func (m *mockMessageConn) Flush() (int, error) {
493494
// the bytes sent into the mock's writtenMessages channel.
494495
func (m *mockMessageConn) WriteMessage(msg []byte) error {
495496
m.writeRaceDetectingCounter++
497+
498+
msgCopy := make([]byte, len(msg))
499+
copy(msgCopy, msg)
500+
496501
select {
497-
case m.writtenMessages <- msg:
502+
case m.writtenMessages <- msgCopy:
498503
case <-time.After(timeout):
499-
m.t.Fatalf("timeout sending message: %v", msg)
504+
m.t.Fatalf("timeout sending message: %v", msgCopy)
500505
}
501506

502507
return nil
@@ -713,6 +718,11 @@ func createTestPeer(t *testing.T) *peerTestCtx {
713718
return nil
714719
},
715720
PongBuf: make([]byte, lnwire.MaxPongBytes),
721+
FetchLastChanUpdate: func(chanID lnwire.ShortChannelID,
722+
) (*lnwire.ChannelUpdate, error) {
723+
724+
return &lnwire.ChannelUpdate{}, nil
725+
},
716726
}
717727

718728
alicePeer := NewBrontide(*cfg)

0 commit comments

Comments
 (0)