@@ -1073,6 +1073,96 @@ func TestPeerCustomMessage(t *testing.T) {
10731073 require .Equal (t , receivedCustomMsg , & receivedCustom .msg )
10741074}
10751075
1076+ // TestPeerIgnoresPingWithoutPongReply ensures we keep the connection alive for
1077+ // pings using the BOLT 1 no-reply sentinel range.
1078+ func TestPeerIgnoresPingWithoutPongReply (t * testing.T ) {
1079+ t .Parallel ()
1080+
1081+ // Arrange: Start a peer using the mock connection so we can
1082+ // inject incoming pings and observe any outgoing responses.
1083+ params := createTestPeer (t )
1084+
1085+ var (
1086+ mockConn = params .mockConn
1087+ alicePeer = params .peer
1088+ )
1089+
1090+ startPeerDone := startPeer (t , mockConn , alicePeer )
1091+ _ , err := fn .RecvOrTimeout (startPeerDone , 2 * timeout )
1092+ require .NoError (t , err )
1093+
1094+ writePing := func (msg * lnwire.Ping ) {
1095+ t .Helper ()
1096+
1097+ var b bytes.Buffer
1098+ _ , err := lnwire .WriteMessage (& b , msg , 0 )
1099+ require .NoError (t , err )
1100+
1101+ select {
1102+ case mockConn .readMessages <- b .Bytes ():
1103+ case <- time .After (timeout ):
1104+ t .Fatal ("timeout sending ping to peer" )
1105+ }
1106+ }
1107+
1108+ // Act: Deliver a ping in the BOLT 1 no-reply range.
1109+ ignoredPayload := []byte {1 , 2 , 3 }
1110+ writePing (& lnwire.Ping {
1111+ NumPongBytes : 65535 ,
1112+ PaddingBytes : ignoredPayload ,
1113+ })
1114+
1115+ // Assert: The peer records the latest ping payload for observability.
1116+ require .Eventually (t , func () bool {
1117+ return bytes .Equal (
1118+ alicePeer .LastRemotePingPayload (), ignoredPayload ,
1119+ )
1120+ }, timeout , 10 * time .Millisecond )
1121+
1122+ // Assert: No pong is sent for the no-reply sentinel range.
1123+ select {
1124+ case rawMsg := <- mockConn .writtenMessages :
1125+ t .Fatalf ("expected no pong reply, got %x" , rawMsg )
1126+ case <- time .After (100 * time .Millisecond ):
1127+ }
1128+
1129+ // Act: Send a normal ping afterward to prove the peer
1130+ // stayed connected and still handles standard ping/pong
1131+ // traffic.
1132+ writePing (& lnwire.Ping {NumPongBytes : 1 })
1133+
1134+ rawMsg , err := fn .RecvOrTimeout (mockConn .writtenMessages , timeout )
1135+ require .NoError (t , err )
1136+
1137+ msg , err := lnwire .ReadMessage (bytes .NewReader (rawMsg ), 0 )
1138+ require .NoError (t , err )
1139+
1140+ // Assert: The follow-up ping receives the requested pong reply.
1141+ pong , ok := msg .(* lnwire.Pong )
1142+ require .True (t , ok )
1143+ require .Len (t , pong .PongBytes , 1 )
1144+ }
1145+
1146+ // TestMessageSummaryPingIncludesNumPongBytes ensures the debug summary for a
1147+ // ping exposes the requested pong size, which makes ignored no-reply pings
1148+ // visible without requiring trace-level logging.
1149+ func TestMessageSummaryPingIncludesNumPongBytes (t * testing.T ) {
1150+ t .Parallel ()
1151+
1152+ // Arrange: Build a ping that uses the BOLT 1 no-reply sentinel range.
1153+ msg := & lnwire.Ping {
1154+ NumPongBytes : 65535 ,
1155+ PaddingBytes : []byte {1 , 2 , 3 },
1156+ }
1157+
1158+ // Act: Generate the human-readable message summary.
1159+ summary := messageSummary (msg )
1160+
1161+ // Assert: The summary includes both the requested pong size and payload
1162+ // length so debug logs can explain why no pong was sent.
1163+ require .Equal (t , "num_pong_bytes=65535, len(ping_bytes)=3" , summary )
1164+ }
1165+
10761166// TestUpdateNextRevocation checks that the method `updateNextRevocation` is
10771167// behave as expected.
10781168func TestUpdateNextRevocation (t * testing.T ) {
0 commit comments