From d47d86ce0c8fadf1f3d6cde8d6740f042405af0e Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Fri, 7 Nov 2025 00:42:00 -0300 Subject: [PATCH] chancloser: stabilize remote RBF coop tests CI started panicking in TestRbfChannelFlushingTransitions/early_offer / TestRbfCloseClosingNegotiationRemote (see GitHub Actions run https://github.com/lightningnetwork/lnd/actions/runs/19155841408/job/54756127218?pr=10352) because the cached remote offer could fire before the test harness registered its mock CloseSigner expectations. When that happened, the mock complained that CreateCloseProposal was unexpected: panic: assert: mock: I don't know what to return because the method call was unexpected. Fix this by having assertSingleRemoteRbfIteration take a sendEvent callback that receives the context and initial offer, so tests can install expectations first and then fire the event via SendEvent (or the early-offer test's custom flush sender). Reproduction (on master) ------------------------ 1. Modify lnwallet/chancloser/rbf_coop_test.go Add time.Sleep(10 * time.Millisecond) before the first call of closeHarness.assertSingleRemoteRbfIteration (in function TestRbfChannelFlushingTransitions). 2. go test ./lnwallet/chancloser -run TestRbfChannelFlushingTransitions/early_offer 3. The panic reproduces immediately. --- lnwallet/chancloser/rbf_coop_test.go | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/lnwallet/chancloser/rbf_coop_test.go b/lnwallet/chancloser/rbf_coop_test.go index 088f7f4e11b..488e41e5ce7 100644 --- a/lnwallet/chancloser/rbf_coop_test.go +++ b/lnwallet/chancloser/rbf_coop_test.go @@ -681,10 +681,16 @@ func (r *rbfCloserTestHarness) assertSingleRbfIteration( r.assertLocalClosePending() } +// assertSingleRemoteRbfIteration asserts that a single RBF iteration initiated +// by the remote party completes successfully. The sendEvent callback controls +// when the event that kicks off the process is sent, which is useful for tests +// that need to set up mocks before the event is processed. The callback is +// provided with the context and the initial offer event so most callers can +// pass chanCloser.SendEvent directly. func (r *rbfCloserTestHarness) assertSingleRemoteRbfIteration( initEvent *OfferReceivedEvent, balanceAfterClose, absoluteFee btcutil.Amount, sequence uint32, iteration bool, - sendInit bool) { + sendEvent func(context.Context, ProtocolEvent)) { ctx := r.T.Context() @@ -696,9 +702,7 @@ func (r *rbfCloserTestHarness) assertSingleRemoteRbfIteration( absoluteFee, balanceAfterClose, false, ) - if sendInit { - r.chanCloser.SendEvent(ctx, initEvent) - } + sendEvent(ctx, initEvent) // Our outer state should transition to ClosingNegotiation state. transitions := []RbfState{ @@ -1386,10 +1390,13 @@ func TestRbfChannelFlushingTransitions(t *testing.T) { // Now we'll send in the channel flushed event, and assert that // this triggers a remote RBF iteration (we process their early // offer and send our sig). - closeHarness.chanCloser.SendEvent(ctx, &flushEvent) closeHarness.assertSingleRemoteRbfIteration( remoteOffer, absoluteFee, absoluteFee, sequence, true, - false, + func(ctx context.Context, _ ProtocolEvent) { + closeHarness.chanCloser.SendEvent( + ctx, &flushEvent, + ) + }, ) }) @@ -1857,7 +1864,7 @@ func TestRbfCloseClosingNegotiationRemote(t *testing.T) { // sig. closeHarness.assertSingleRemoteRbfIteration( feeOffer, balanceAfterClose, absoluteFee, sequence, - false, true, + false, closeHarness.chanCloser.SendEvent, ) // Next, we'll receive an offer from the remote party, and drive @@ -1867,7 +1874,7 @@ func TestRbfCloseClosingNegotiationRemote(t *testing.T) { absoluteFee = feeOffer.SigMsg.FeeSatoshis closeHarness.assertSingleRemoteRbfIteration( feeOffer, balanceAfterClose, absoluteFee, sequence, - true, true, + true, closeHarness.chanCloser.SendEvent, ) closeHarness.assertNoStateTransitions() @@ -1950,7 +1957,7 @@ func TestRbfCloseClosingNegotiationRemote(t *testing.T) { // sig. closeHarness.assertSingleRemoteRbfIteration( feeOffer, balanceAfterClose, absoluteFee, sequence, - false, true, + false, closeHarness.chanCloser.SendEvent, ) }) @@ -2048,7 +2055,7 @@ func TestRbfCloseErr(t *testing.T) { // sig. closeHarness.assertSingleRemoteRbfIteration( feeOffer, balanceAfterClose, absoluteFee, sequence, - true, true, + true, closeHarness.chanCloser.SendEvent, ) })