mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-25 19:46:52 +02:00
channeldb: return error when payment is not initialized
This commit changes `fetchPaymentStatus` to return an error when the payment creation info bucket cannot be found. Instead of using the ambiguous status `StatusUnknown`, we tell the callsite explictly that there's no such payment. This also means the vague `StatusUnknown` can now be removed as it has multiple meanings.
This commit is contained in:
committed by
Olaoluwa Osuntokun
parent
21cecc40e1
commit
6be3817eed
@@ -141,36 +141,40 @@ func (p *PaymentControl) InitPayment(paymentHash lntypes.Hash,
|
|||||||
|
|
||||||
// Get the existing status of this payment, if any.
|
// Get the existing status of this payment, if any.
|
||||||
paymentStatus, err := fetchPaymentStatus(bucket)
|
paymentStatus, err := fetchPaymentStatus(bucket)
|
||||||
if err != nil {
|
|
||||||
|
switch {
|
||||||
|
// If no error is returned, it means we already have this
|
||||||
|
// 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 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
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, if the error is not `ErrPaymentNotInitiated`,
|
||||||
|
// we'll return the error.
|
||||||
|
case !errors.Is(err, ErrPaymentNotInitiated):
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch paymentStatus {
|
|
||||||
|
|
||||||
// We allow retrying failed payments.
|
|
||||||
case StatusFailed:
|
|
||||||
|
|
||||||
// This is a new payment that is being initialized for the
|
|
||||||
// first time.
|
|
||||||
case StatusUnknown:
|
|
||||||
|
|
||||||
// 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
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Before we set our new sequence number, we check whether this
|
// Before we set our new sequence number, we check whether this
|
||||||
// payment has a previously set sequence number and remove its
|
// payment has a previously set sequence number and remove its
|
||||||
// index entry if it exists. This happens in the case where we
|
// index entry if it exists. This happens in the case where we
|
||||||
@@ -530,14 +534,12 @@ func (p *PaymentControl) Fail(paymentHash lntypes.Hash,
|
|||||||
// lets the last attempt to fail with a terminal write its
|
// lets the last attempt to fail with a terminal write its
|
||||||
// failure to the PaymentControl without synchronizing with
|
// failure to the PaymentControl without synchronizing with
|
||||||
// other attempts.
|
// other attempts.
|
||||||
paymentStatus, err := fetchPaymentStatus(bucket)
|
_, err = fetchPaymentStatus(bucket)
|
||||||
if err != nil {
|
if errors.Is(err, ErrPaymentNotInitiated) {
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if paymentStatus == StatusUnknown {
|
|
||||||
updateErr = ErrPaymentNotInitiated
|
updateErr = ErrPaymentNotInitiated
|
||||||
return nil
|
return nil
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put the failure reason in the bucket for record keeping.
|
// Put the failure reason in the bucket for record keeping.
|
||||||
@@ -702,12 +704,12 @@ func (p *PaymentControl) nextPaymentSequence() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fetchPaymentStatus fetches the payment status of the payment. If the payment
|
// fetchPaymentStatus fetches the payment status of the payment. If the payment
|
||||||
// isn't found, it will default to "StatusUnknown".
|
// isn't found, it will return error `ErrPaymentNotInitiated`.
|
||||||
func fetchPaymentStatus(bucket kvdb.RBucket) (PaymentStatus, error) {
|
func fetchPaymentStatus(bucket kvdb.RBucket) (PaymentStatus, error) {
|
||||||
// Creation info should be set for all payments, regardless of state.
|
// Creation info should be set for all payments, regardless of state.
|
||||||
// If not, it is unknown.
|
// If not, it is unknown.
|
||||||
if bucket.Get(paymentCreationInfoKey) == nil {
|
if bucket.Get(paymentCreationInfoKey) == nil {
|
||||||
return StatusUnknown, nil
|
return 0, ErrPaymentNotInitiated
|
||||||
}
|
}
|
||||||
|
|
||||||
payment, err := fetchPayment(bucket)
|
payment, err := fetchPayment(bucket)
|
||||||
@@ -730,11 +732,6 @@ func ensureInFlight(payment *MPPayment) error {
|
|||||||
case paymentStatus == StatusInFlight:
|
case paymentStatus == StatusInFlight:
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
// Our records show the payment as unknown, meaning it never
|
|
||||||
// should have left the switch.
|
|
||||||
case paymentStatus == StatusUnknown:
|
|
||||||
return ErrPaymentNotInitiated
|
|
||||||
|
|
||||||
// The payment succeeded previously.
|
// The payment succeeded previously.
|
||||||
case paymentStatus == StatusSucceeded:
|
case paymentStatus == StatusSucceeded:
|
||||||
return ErrPaymentAlreadySucceeded
|
return ErrPaymentAlreadySucceeded
|
||||||
|
@@ -273,8 +273,6 @@ func TestPaymentControlSuccessesWithoutInFlight(t *testing.T) {
|
|||||||
if err != ErrPaymentNotInitiated {
|
if err != ErrPaymentNotInitiated {
|
||||||
t.Fatalf("expected ErrPaymentNotInitiated, got %v", err)
|
t.Fatalf("expected ErrPaymentNotInitiated, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusUnknown)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestPaymentControlFailsWithoutInFlight checks that a strict payment
|
// TestPaymentControlFailsWithoutInFlight checks that a strict payment
|
||||||
@@ -295,8 +293,6 @@ func TestPaymentControlFailsWithoutInFlight(t *testing.T) {
|
|||||||
if err != ErrPaymentNotInitiated {
|
if err != ErrPaymentNotInitiated {
|
||||||
t.Fatalf("expected ErrPaymentNotInitiated, got %v", err)
|
t.Fatalf("expected ErrPaymentNotInitiated, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusUnknown)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestPaymentControlDeleteNonInFlight checks that calling DeletePayments only
|
// TestPaymentControlDeleteNonInFlight checks that calling DeletePayments only
|
||||||
@@ -1085,7 +1081,7 @@ func assertPaymentStatus(t *testing.T, p *PaymentControl,
|
|||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
payment, err := p.FetchPayment(hash)
|
payment, err := p.FetchPayment(hash)
|
||||||
if expStatus == StatusUnknown && err == ErrPaymentNotInitiated {
|
if err == ErrPaymentNotInitiated {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -4,9 +4,8 @@ package channeldb
|
|||||||
type PaymentStatus byte
|
type PaymentStatus byte
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// StatusUnknown is the status where a payment has never been initiated
|
// NOTE: PaymentStatus = 0 was previously used for status unknown and
|
||||||
// and hence is unknown.
|
// is now deprecated.
|
||||||
StatusUnknown PaymentStatus = 0
|
|
||||||
|
|
||||||
// StatusInFlight is the status where a payment has been initiated, but
|
// StatusInFlight is the status where a payment has been initiated, but
|
||||||
// a response has not been received.
|
// a response has not been received.
|
||||||
@@ -24,9 +23,6 @@ const (
|
|||||||
// String returns readable representation of payment status.
|
// String returns readable representation of payment status.
|
||||||
func (ps PaymentStatus) String() string {
|
func (ps PaymentStatus) String() string {
|
||||||
switch ps {
|
switch ps {
|
||||||
case StatusUnknown:
|
|
||||||
return "Unknown"
|
|
||||||
|
|
||||||
case StatusInFlight:
|
case StatusInFlight:
|
||||||
return "In Flight"
|
return "In Flight"
|
||||||
|
|
||||||
|
@@ -1370,9 +1370,6 @@ func convertPaymentStatus(dbStatus channeldb.PaymentStatus) (
|
|||||||
lnrpc.Payment_PaymentStatus, error) {
|
lnrpc.Payment_PaymentStatus, error) {
|
||||||
|
|
||||||
switch dbStatus {
|
switch dbStatus {
|
||||||
case channeldb.StatusUnknown:
|
|
||||||
return lnrpc.Payment_UNKNOWN, nil
|
|
||||||
|
|
||||||
case channeldb.StatusInFlight:
|
case channeldb.StatusInFlight:
|
||||||
return lnrpc.Payment_IN_FLIGHT, nil
|
return lnrpc.Payment_IN_FLIGHT, nil
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user