htlcswitch: add test for deferred processing remote adds when quiescent

This commit is contained in:
Keagan McClelland 2024-04-09 17:48:56 -07:00
parent 4fbab45a5f
commit 5906ca2537
No known key found for this signature in database
GPG Key ID: FA7E65C951F12439
2 changed files with 99 additions and 2 deletions

View File

@ -7540,3 +7540,92 @@ func TestLinkFlushHooksCalled(t *testing.T) {
ctx.receiveRevAndAckAliceToBob()
assertHookCalled(true)
}
// TestLinkQuiescenceExitHopProcessingDeferred ensures that we do not send back
// htlc resolution messages in the case where the link is quiescent AND we are
// the exit hop. This is needed because we handle exit hop processing in the
// link instead of the switch and we process htlc resolutions when we receive
// a RevokeAndAck. Because of this we need to ensure that we hold off on
// processing the remote adds when we are quiescent. Later, when the channel
// update traffic is allowed to resume, we will need to verify that the actions
// we didn't run during the initial RevokeAndAck are run.
func TestLinkQuiescenceExitHopProcessingDeferred(t *testing.T) {
t.Parallel()
// Initialize two channel state machines for testing.
alice, bob, err := createMirroredChannel(
t, btcutil.SatoshiPerBitcoin, btcutil.SatoshiPerBitcoin,
)
require.NoError(t, err)
// Build a single edge network to test channel quiescence.
network := newTwoHopNetwork(
t, alice.channel, bob.channel, testStartingHeight,
)
aliceLink := network.aliceChannelLink
bobLink := network.bobChannelLink
// Generate an invoice for Bob so that Alice can pay him.
htlcID := uint64(0)
htlc, invoice := generateHtlcAndInvoice(t, htlcID)
err = network.bobServer.registry.AddInvoice(
nil, *invoice, htlc.PaymentHash,
)
require.NoError(t, err)
// Establish a payment circuit for Alice
circuit := &PaymentCircuit{
Incoming: CircuitKey{
HtlcID: htlcID,
},
PaymentHash: htlc.PaymentHash,
}
circuitMap := network.aliceServer.htlcSwitch.circuits
_, err = circuitMap.CommitCircuits(circuit)
require.NoError(t, err)
// Add a switch packet to Alice's switch so that she can initialize the
// payment attempt.
err = aliceLink.handleSwitchPacket(&htlcPacket{
incomingHTLCID: htlcID,
htlc: htlc,
circuit: circuit,
})
require.NoError(t, err)
// give alice enough time to fire the update_add
// TODO(proofofkeags): make this not depend on a flakey sleep.
<-time.After(time.Millisecond)
// bob initiates stfu which he can do immediately since he doesn't have
// local updates
<-bobLink.InitStfu()
// wait for other possible messages to play out
<-time.After(1 * time.Second)
ensureNoUpdateAfterStfu := func(t *testing.T, trace []lnwire.Message) {
stfuReceived := false
for _, msg := range trace {
if msg.MsgType() == lnwire.MsgStfu {
stfuReceived = true
continue
}
if stfuReceived && msg.MsgType().IsChannelUpdate() {
t.Fatalf("channel update after stfu: %v",
msg.MsgType())
}
}
}
network.aliceServer.protocolTraceMtx.Lock()
ensureNoUpdateAfterStfu(t, network.aliceServer.protocolTrace)
network.aliceServer.protocolTraceMtx.Unlock()
network.bobServer.protocolTraceMtx.Lock()
ensureNoUpdateAfterStfu(t, network.bobServer.protocolTrace)
network.bobServer.protocolTraceMtx.Unlock()
// TODO(proofofkeags): make sure these actions are run on resume.
}

View File

@ -153,8 +153,10 @@ type mockServer struct {
t testing.TB
name string
messages chan lnwire.Message
name string
messages chan lnwire.Message
protocolTraceMtx sync.Mutex
protocolTrace []lnwire.Message
id [33]byte
htlcSwitch *Switch
@ -289,6 +291,10 @@ func (s *mockServer) Start() error {
for {
select {
case msg := <-s.messages:
s.protocolTraceMtx.Lock()
s.protocolTrace = append(s.protocolTrace, msg)
s.protocolTraceMtx.Unlock()
var shouldSkip bool
for _, interceptor := range s.interceptorFuncs {
@ -627,6 +633,8 @@ func (s *mockServer) readHandler(message lnwire.Message) error {
targetChan = msg.ChanID
case *lnwire.UpdateFee:
targetChan = msg.ChanID
case *lnwire.Stfu:
targetChan = msg.ChanID
default:
return fmt.Errorf("unknown message type: %T", msg)
}