openchannel: cancel shims with a live context

In manager.go, deferred shim cleanup was calling
FundingStateStep with the original request ctx.
If the user had already canceled that context,
the cleanup RPC would run with a canceled context
and could fail to remove the pending shim. I changed
that cleanup path to use context.WithoutCancel(ctx)
so the cancellation RPC still has a live context.
This commit is contained in:
Slyghtning 2026-02-28 11:54:55 +01:00
parent 0b295123e7
commit 3e526faf82
No known key found for this signature in database
GPG key ID: F82D456EA023C9BF
2 changed files with 46 additions and 10 deletions

View file

@ -458,9 +458,7 @@ func (m *Manager) openChannelPsbt(ctx context.Context,
log.Infof("Starting PSBT funding flow with pending channel ID %x.\n",
pendingChanID)
// maybeCancelShim is a helper function that cancels the funding shim
// with the RPC server in case we end up aborting early.
maybeCancelShim := func() {
defer func() {
shimMu.Lock()
defer shimMu.Unlock()
@ -478,15 +476,14 @@ func (m *Manager) openChannelPsbt(ctx context.Context,
},
}
_, err := m.cfg.LightningClient.FundingStateStep(
ctx, cancelMsg,
context.WithoutCancel(ctx), cancelMsg,
)
if err != nil {
log.Errorf("Error canceling shim: %v\n", err)
}
shimPending = false
}
}
defer maybeCancelShim()
}()
// Create the PSBT funding shim that will tell the funding manager we
// want to use a PSBT.

View file

@ -608,9 +608,10 @@ type mockLndClient struct {
rawClient lnrpc.LightningClient
mu sync.Mutex
fundingStepIdx int
fundingStepErr error
mu sync.Mutex
fundingStepIdx int
fundingStepErr error
fundingStepCtxErrs []error
}
func (m *mockLndClient) RawClientWithMacAuth(
@ -620,13 +621,14 @@ func (m *mockLndClient) RawClientWithMacAuth(
return ctx, 0, m.rawClient
}
func (m *mockLndClient) FundingStateStep(_ context.Context,
func (m *mockLndClient) FundingStateStep(ctx context.Context,
_ *lnrpc.FundingTransitionMsg) (*lnrpc.FundingStateStepResp, error) {
m.mu.Lock()
defer m.mu.Unlock()
m.fundingStepIdx++
m.fundingStepCtxErrs = append(m.fundingStepCtxErrs, ctx.Err())
return &lnrpc.FundingStateStepResp{}, m.fundingStepErr
}
@ -746,6 +748,43 @@ func TestStreamOpenError(t *testing.T) {
// Verify that the shim was canceled via FundingStateStep.
lnClient.mu.Lock()
require.Equal(t, 1, lnClient.fundingStepIdx)
require.Len(t, lnClient.fundingStepCtxErrs, 1)
require.NoError(t, lnClient.fundingStepCtxErrs[0])
lnClient.mu.Unlock()
}
// TestStreamOpenErrorWithCanceledContext verifies that deferred shim cleanup
// still uses a live context even if the caller canceled the original request.
func TestStreamOpenErrorWithCanceledContext(t *testing.T) {
t.Parallel()
mockRaw := &mockRawLnrpcClient{
openErr: errors.New("connection refused"),
}
lnClient := &mockLndClient{rawClient: mockRaw}
manager := &Manager{
cfg: &Config{
LightningClient: lnClient,
ChainParams: &chaincfg.RegressionNetParams,
},
}
ctx, cancel := context.WithCancel(context.Background())
cancel()
req := &lnrpc.OpenChannelRequest{
LocalFundingAmount: 100000,
MinConfs: defaultUtxoMinConf,
}
_, err := manager.openChannelPsbt(ctx, req, nil, 0)
require.ErrorContains(t, err, "opening stream to server failed")
lnClient.mu.Lock()
require.Equal(t, 1, lnClient.fundingStepIdx)
require.Len(t, lnClient.fundingStepCtxErrs, 1)
require.NoError(t, lnClient.fundingStepCtxErrs[0])
lnClient.mu.Unlock()
}