diff --git a/instantout/actions.go b/instantout/actions.go index d1c405fd8..bc297f843 100644 --- a/instantout/actions.go +++ b/instantout/actions.go @@ -244,7 +244,13 @@ func (f *FSM) PollPaymentAcceptedAction(ctx context.Context, timer := time.NewTimer(time.Second) for { select { - case payRes := <-payChan: + case payRes, ok := <-payChan: + if !ok { + return f.handleErrorAndUnlockReservations( + ctx, errors.New("payment status channel closed"), + ) + } + f.Debugf("payment result: %v", payRes) if payRes.State == lnrpc.Payment_FAILED { return f.handleErrorAndUnlockReservations( @@ -252,12 +258,18 @@ func (f *FSM) PollPaymentAcceptedAction(ctx context.Context, payRes.FailureReason), ) } - case err := <-paymentErrChan: + case err, ok := <-paymentErrChan: + if !ok { + err = errors.New("payment error channel closed") + } else if err == nil { + err = errors.New("payment error channel returned nil") + } + f.Errorf("error sending payment: %v", err) return f.handleErrorAndUnlockReservations(ctx, err) case <-ctx.Done(): - return f.handleErrorAndUnlockReservations(ctx, nil) + return f.handleErrorAndUnlockReservations(ctx, ctx.Err()) case <-timer.C: res, err := f.cfg.InstantOutClient.PollPaymentAccepted( @@ -620,13 +632,15 @@ func (f *FSM) handleErrorAndUnlockReservations(ctx context.Context, err error) fsm.EventType { // We might get here from a canceled context, we create a new context // with a timeout to unlock the reservations. - ctx, cancel := context.WithTimeout(ctx, time.Second*30) + unlockCtx, cancel := context.WithTimeout( + context.Background(), time.Second*30, + ) defer cancel() // Unlock the reservations. for _, reservation := range f.InstantOut.Reservations { err := f.cfg.ReservationManager.UnlockReservation( - ctx, reservation.ID, + unlockCtx, reservation.ID, ) if err != nil { f.Errorf("error unlocking reservation: %v", err) @@ -638,7 +652,9 @@ func (f *FSM) handleErrorAndUnlockReservations(ctx context.Context, // release the reservations. This can be done in a goroutine as we // wan't to fail the fsm early. go func() { - ctx, cancel := context.WithTimeout(ctx, time.Second*30) + ctx, cancel := context.WithTimeout( + context.Background(), time.Second*30, + ) defer cancel() _, cancelErr := f.cfg.InstantOutClient.CancelInstantSwap( ctx, &swapserverrpc.CancelInstantSwapRequest{ diff --git a/instantout/instantout.go b/instantout/instantout.go index f8c89eb0c..d9405ffaf 100644 --- a/instantout/instantout.go +++ b/instantout/instantout.go @@ -263,6 +263,12 @@ func (i *InstantOut) signMusig2Tx(ctx context.Context, if err != nil { return nil, err } + if len(musig2sessions) != len(inputs) { + return nil, fmt.Errorf("invalid number of MuSig2 sessions") + } + if len(counterPartyNonces) != len(inputs) { + return nil, fmt.Errorf("invalid number of peer nonces") + } prevOutFetcher := inputs.GetPrevoutFetcher() sigHashes := txscript.NewTxSigHashes(tx, prevOutFetcher) @@ -329,6 +335,12 @@ func (i *InstantOut) finalizeMusig2Transaction(ctx context.Context, if err != nil { return nil, err } + if len(musig2Sessions) != len(inputs) { + return nil, fmt.Errorf("invalid number of MuSig2 sessions") + } + if len(serverSigs) != len(inputs) { + return nil, fmt.Errorf("invalid number of peer signatures") + } for idx := range inputs { haveAllSigs, finalSig, err := signer.MuSig2CombineSig( diff --git a/instantout/manager.go b/instantout/manager.go index 37ccb681b..be895e18f 100644 --- a/instantout/manager.go +++ b/instantout/manager.go @@ -159,14 +159,12 @@ func (m *Manager) NewInstantOut(ctx context.Context, protocolVersion: CurrentProtocolVersion(), sweepAddress: sweepAddr, } + m.Unlock() instantOut, err := NewFSM(m.cfg, ProtocolVersionFullReservation) if err != nil { - m.Unlock() return nil, err } - m.activeInstantOuts[instantOut.InstantOut.SwapHash] = instantOut - m.Unlock() // Start the instantout FSM. go func() { @@ -186,6 +184,10 @@ func (m *Manager) NewInstantOut(ctx context.Context, return nil, err } + m.Lock() + m.activeInstantOuts[instantOut.InstantOut.SwapHash] = instantOut + m.Unlock() + return instantOut, nil }