channeldb: add new payment status StatusInitiated

This commit adds a new payment status, `StatusInitiated`, to properly
represent the state where a payment is newly created without attempting
any HTLCs. Since the `PaymentStatus` is a memory representation of a
given payment's status, the enum used for the statuses are directly
updated.
This commit is contained in:
yyforyongyu 2022-11-24 12:05:48 +08:00 committed by Olaoluwa Osuntokun
parent 6be3817eed
commit 30fd29371c
4 changed files with 35 additions and 8 deletions

View file

@ -26,6 +26,10 @@ var (
// already "in flight" on the network.
ErrPaymentInFlight = errors.New("payment is in transition")
// ErrPaymentExists is returned when we try to initialize an already
// existing payment that is not failed.
ErrPaymentExists = errors.New("payment already exists")
// ErrPaymentNotInitiated is returned if the payment wasn't initiated.
ErrPaymentNotInitiated = errors.New("payment isn't initiated")
@ -148,10 +152,15 @@ func (p *PaymentControl) InitPayment(paymentHash lntypes.Hash,
// 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:
@ -727,6 +736,9 @@ func ensureInFlight(payment *MPPayment) error {
paymentStatus := payment.Status
switch {
// Newly created payment is also inflight.
case paymentStatus == StatusInitiated:
return nil
// The payment was indeed InFlight.
case paymentStatus == StatusInFlight:

View file

@ -7,22 +7,29 @@ const (
// NOTE: PaymentStatus = 0 was previously used for status unknown and
// is now deprecated.
// StatusInitiated is the status where a payment has just been
// initiated.
StatusInitiated PaymentStatus = 1
// StatusInFlight is the status where a payment has been initiated, but
// a response has not been received.
StatusInFlight PaymentStatus = 1
StatusInFlight PaymentStatus = 2
// StatusSucceeded is the status where a payment has been initiated and
// the payment was completed successfully.
StatusSucceeded PaymentStatus = 2
StatusSucceeded PaymentStatus = 3
// StatusFailed is the status where a payment has been initiated and a
// failure result has come back.
StatusFailed PaymentStatus = 3
StatusFailed PaymentStatus = 4
)
// String returns readable representation of payment status.
func (ps PaymentStatus) String() string {
switch ps {
case StatusInitiated:
return "Initiated"
case StatusInFlight:
return "In Flight"

View file

@ -446,10 +446,17 @@ func (s *Server) SendToRouteV2(ctx context.Context,
}
// Transform user errors to grpc code.
if err == channeldb.ErrPaymentInFlight ||
err == channeldb.ErrAlreadyPaid {
switch {
case errors.Is(err, channeldb.ErrPaymentExists):
fallthrough
return nil, status.Error(codes.AlreadyExists, err.Error())
case errors.Is(err, channeldb.ErrPaymentInFlight):
fallthrough
case errors.Is(err, channeldb.ErrAlreadyPaid):
return nil, status.Error(
codes.AlreadyExists, err.Error(),
)
}
return nil, err

View file

@ -2276,7 +2276,8 @@ func (r *ChannelRouter) sendToRoute(htlcHash lntypes.Hash, rt *route.Route,
switch {
// If this is an MPP attempt and the hash is already registered with
// the database, we can go on to launch the shard.
case err == channeldb.ErrPaymentInFlight && mpp != nil:
case mpp != nil && errors.Is(err, channeldb.ErrPaymentInFlight):
case mpp != nil && errors.Is(err, channeldb.ErrPaymentExists):
// Any other error is not tolerated.
case err != nil: