diff --git a/itest/lnd_quiescence_test.go b/itest/lnd_quiescence_test.go index a00c00189..c60f93842 100644 --- a/itest/lnd_quiescence_test.go +++ b/itest/lnd_quiescence_test.go @@ -14,9 +14,16 @@ import ( // channel. We initiate quiescence via RPC and if it succeeds we verify that // the expected initiator is the resulting initiator. func testQuiescence(ht *lntest.HarnessTest) { - cfg := node.CfgAnchor + aCfg := node.CfgAnchor + bCfg := node.CfgAnchor + + // Use different minbackoff values for Alice and Bob to avoid connection + // race. See https://github.com/lightningnetwork/lnd/issues/6788. + aCfg = append(aCfg, "--minbackoff=1s") + bCfg = append(bCfg, "--minbackoff=60s") + chanPoints, nodes := ht.CreateSimpleNetwork( - [][]string{cfg, cfg}, lntest.OpenChannelParams{ + [][]string{aCfg, bCfg}, lntest.OpenChannelParams{ Amt: btcutil.Amount(1000000), }) @@ -60,4 +67,48 @@ func testQuiescence(ht *lntest.HarnessTest) { alice, req, lnrpc.PaymentFailureReason_FAILURE_REASON_INSUFFICIENT_BALANCE, ) + + // Bob now subscribes the peer events, which will be used to assert the + // connection updates. + client := bob.RPC.SubscribePeerEvents(&lnrpc.PeerEventSubscription{}) + + // Alice now restarts with an extremely short quiescence timeout. + ht.RestartNodeWithExtraArgs( + alice, []string{"--htlcswitch.quiescencetimeout=1ms"}, + ) + + // Bob should be reconnected to Alice. + ht.AssertPeerReconnected(client) + + // Once restarted, the channel is no longer quiescent so Alice can + // finish the payment for invoice2. + ht.SendPaymentAssertSettled(alice, req) + + // Bob adds another invoice. + invoice3 := bob.RPC.AddInvoice(invReq) + + // Alice now requires the channel to be quiescent again. Since we are + // using a short timeout (1ms) for the quiescence, Alice should + // disconnect from Bob immediately. + res = alice.RPC.Quiesce(&devrpc.QuiescenceRequest{ + ChanId: chanPoint, + }) + require.True(ht, res.Initiator) + + // The above quiescence timeout will cause Alice to disconnect with Bob. + // However, since the connection has an open channel, Alice and Bob will + // be reconnected shortly. + ht.AssertPeerReconnected(client) + + // Make sure Alice has finished the connection too before attempting the + // payment below. + ht.AssertConnected(alice, bob) + + // Assert that Alice can pay invoice3. This implicitly checks that the + // above quiescence is terminated. + req = &routerrpc.SendPaymentRequest{ + PaymentRequest: invoice3.PaymentRequest, + FeeLimitMsat: noFeeLimitMsat, + } + ht.SendPaymentAssertSettled(alice, req) } diff --git a/lncfg/htlcswitch.go b/lncfg/htlcswitch.go index 9942df22b..12c421ca7 100644 --- a/lncfg/htlcswitch.go +++ b/lncfg/htlcswitch.go @@ -40,7 +40,9 @@ func (h *Htlcswitch) Validate() error { MaxMailboxDeliveryTimeout) } - if h.QuiescenceTimeout < minQuiescenceTimeout { + // Skip the validation for integration tests so we can use a smaller + // timeout value to check the timeout behavior. + if !IsDevBuild() && h.QuiescenceTimeout < minQuiescenceTimeout { return fmt.Errorf("quiescencetimeout: %v below minimal: %v", h.QuiescenceTimeout, minQuiescenceTimeout) }