diff --git a/channeldb/payment_control.go b/channeldb/payment_control.go index 2f22d4c77..2d13e2585 100644 --- a/channeldb/payment_control.go +++ b/channeldb/payment_control.go @@ -151,30 +151,8 @@ func (p *PaymentControl) InitPayment(paymentHash lntypes.Hash, // payment. We'll check the status to decide whether we allow // retrying the payment or return a specific error. case err == nil: - switch paymentStatus { - // We allow retrying failed payments. - case StatusFailed: - - // We already have payment creation info for this - // payment so we won't allow creating a duplicate one. - case StatusInitiated: - updateErr = ErrPaymentExists - return nil - - // We already have an InFlight payment on the network. - // We will disallow any new payments. - case StatusInFlight: - updateErr = ErrPaymentInFlight - return nil - - // We've already succeeded a payment to this payment - // hash, forbid the switch from sending another. - case StatusSucceeded: - updateErr = ErrAlreadyPaid - return nil - - default: - updateErr = ErrUnknownPaymentStatus + if err := paymentStatus.initializable(); err != nil { + updateErr = err return nil } diff --git a/channeldb/payment_status.go b/channeldb/payment_status.go index 38ef5a047..2d19546a2 100644 --- a/channeldb/payment_status.go +++ b/channeldb/payment_status.go @@ -1,5 +1,7 @@ package channeldb +import "fmt" + // PaymentStatus represent current status of payment. type PaymentStatus byte @@ -43,3 +45,33 @@ func (ps PaymentStatus) String() string { return "Unknown" } } + +// initializable returns an error to specify whether initiating the payment +// with its current status is allowed. A payment can only be initialized if it +// hasn't been created yet or already failed. +func (ps PaymentStatus) initializable() error { + switch ps { + // The payment has been created already. We will disallow creating it + // again in case other goroutines have already been creating HTLCs for + // it. + case StatusInitiated: + return ErrPaymentExists + + // We already have an InFlight payment on the network. We will disallow + // any new payments. + case StatusInFlight: + return ErrPaymentInFlight + + // The payment has been attempted and is succeeded so we won't allow + // creating it again. + case StatusSucceeded: + return ErrAlreadyPaid + + // We allow retrying failed payments. + case StatusFailed: + return nil + + default: + return fmt.Errorf("%w: %v", ErrUnknownPaymentStatus, ps) + } +}