github.com/decred/dcrlnd@v0.7.6/channeldb/payment_control.go (about)

     1  package channeldb
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"sync"
    10  
    11  	"github.com/decred/dcrlnd/kvdb"
    12  	"github.com/decred/dcrlnd/lntypes"
    13  )
    14  
    15  const (
    16  	// paymentSeqBlockSize is the block size used when we batch allocate
    17  	// payment sequences for future payments.
    18  	paymentSeqBlockSize = 1000
    19  )
    20  
    21  var (
    22  	// ErrAlreadyPaid signals we have already paid this payment hash.
    23  	ErrAlreadyPaid = errors.New("invoice is already paid")
    24  
    25  	// ErrPaymentInFlight signals that payment for this payment hash is
    26  	// already "in flight" on the network.
    27  	ErrPaymentInFlight = errors.New("payment is in transition")
    28  
    29  	// ErrPaymentNotInitiated is returned if the payment wasn't initiated.
    30  	ErrPaymentNotInitiated = errors.New("payment isn't initiated")
    31  
    32  	// ErrPaymentAlreadySucceeded is returned in the event we attempt to
    33  	// change the status of a payment already succeeded.
    34  	ErrPaymentAlreadySucceeded = errors.New("payment is already succeeded")
    35  
    36  	// ErrPaymentAlreadyFailed is returned in the event we attempt to alter
    37  	// a failed payment.
    38  	ErrPaymentAlreadyFailed = errors.New("payment has already failed")
    39  
    40  	// ErrUnknownPaymentStatus is returned when we do not recognize the
    41  	// existing state of a payment.
    42  	ErrUnknownPaymentStatus = errors.New("unknown payment status")
    43  
    44  	// ErrPaymentTerminal is returned if we attempt to alter a payment that
    45  	// already has reached a terminal condition.
    46  	ErrPaymentTerminal = errors.New("payment has reached terminal condition")
    47  
    48  	// ErrAttemptAlreadySettled is returned if we try to alter an already
    49  	// settled HTLC attempt.
    50  	ErrAttemptAlreadySettled = errors.New("attempt already settled")
    51  
    52  	// ErrAttemptAlreadyFailed is returned if we try to alter an already
    53  	// failed HTLC attempt.
    54  	ErrAttemptAlreadyFailed = errors.New("attempt already failed")
    55  
    56  	// ErrValueMismatch is returned if we try to register a non-MPP attempt
    57  	// with an amount that doesn't match the payment amount.
    58  	ErrValueMismatch = errors.New("attempted value doesn't match payment" +
    59  		"amount")
    60  
    61  	// ErrValueExceedsAmt is returned if we try to register an attempt that
    62  	// would take the total sent amount above the payment amount.
    63  	ErrValueExceedsAmt = errors.New("attempted value exceeds payment" +
    64  		"amount")
    65  
    66  	// ErrNonMPPayment is returned if we try to register an MPP attempt for
    67  	// a payment that already has a non-MPP attempt regitered.
    68  	ErrNonMPPayment = errors.New("payment has non-MPP attempts")
    69  
    70  	// ErrMPPayment is returned if we try to register a non-MPP attempt for
    71  	// a payment that already has an MPP attempt regitered.
    72  	ErrMPPayment = errors.New("payment has MPP attempts")
    73  
    74  	// ErrMPPPaymentAddrMismatch is returned if we try to register an MPP
    75  	// shard where the payment address doesn't match existing shards.
    76  	ErrMPPPaymentAddrMismatch = errors.New("payment address mismatch")
    77  
    78  	// ErrMPPTotalAmountMismatch is returned if we try to register an MPP
    79  	// shard where the total amount doesn't match existing shards.
    80  	ErrMPPTotalAmountMismatch = errors.New("mp payment total amount mismatch")
    81  
    82  	// errNoAttemptInfo is returned when no attempt info is stored yet.
    83  	errNoAttemptInfo = errors.New("unable to find attempt info for " +
    84  		"inflight payment")
    85  
    86  	// errNoSequenceNrIndex is returned when an attempt to lookup a payment
    87  	// index is made for a sequence number that is not indexed.
    88  	errNoSequenceNrIndex = errors.New("payment sequence number index " +
    89  		"does not exist")
    90  )
    91  
    92  // PaymentControl implements persistence for payments and payment attempts.
    93  type PaymentControl struct {
    94  	paymentSeqMx     sync.Mutex
    95  	currPaymentSeq   uint64
    96  	storedPaymentSeq uint64
    97  	db               *DB
    98  }
    99  
   100  // NewPaymentControl creates a new instance of the PaymentControl.
   101  func NewPaymentControl(db *DB) *PaymentControl {
   102  	return &PaymentControl{
   103  		db: db,
   104  	}
   105  }
   106  
   107  // InitPayment checks or records the given PaymentCreationInfo with the DB,
   108  // making sure it does not already exist as an in-flight payment. When this
   109  // method returns successfully, the payment is guranteeed to be in the InFlight
   110  // state.
   111  func (p *PaymentControl) InitPayment(paymentHash lntypes.Hash,
   112  	info *PaymentCreationInfo) error {
   113  
   114  	// Obtain a new sequence number for this payment. This is used
   115  	// to sort the payments in order of creation, and also acts as
   116  	// a unique identifier for each payment.
   117  	sequenceNum, err := p.nextPaymentSequence()
   118  	if err != nil {
   119  		return err
   120  	}
   121  
   122  	var b bytes.Buffer
   123  	if err := serializePaymentCreationInfo(&b, info); err != nil {
   124  		return err
   125  	}
   126  	infoBytes := b.Bytes()
   127  
   128  	var updateErr error
   129  	err = kvdb.Batch(p.db.Backend, func(tx kvdb.RwTx) error {
   130  		// Reset the update error, to avoid carrying over an error
   131  		// from a previous execution of the batched db transaction.
   132  		updateErr = nil
   133  
   134  		prefetchPayment(tx, paymentHash)
   135  		bucket, err := createPaymentBucket(tx, paymentHash)
   136  		if err != nil {
   137  			return err
   138  		}
   139  
   140  		// Get the existing status of this payment, if any.
   141  		paymentStatus, err := fetchPaymentStatus(bucket)
   142  		if err != nil {
   143  			return err
   144  		}
   145  
   146  		switch paymentStatus {
   147  
   148  		// We allow retrying failed payments.
   149  		case StatusFailed:
   150  
   151  		// This is a new payment that is being initialized for the
   152  		// first time.
   153  		case StatusUnknown:
   154  
   155  		// We already have an InFlight payment on the network. We will
   156  		// disallow any new payments.
   157  		case StatusInFlight:
   158  			updateErr = ErrPaymentInFlight
   159  			return nil
   160  
   161  		// We've already succeeded a payment to this payment hash,
   162  		// forbid the switch from sending another.
   163  		case StatusSucceeded:
   164  			updateErr = ErrAlreadyPaid
   165  			return nil
   166  
   167  		default:
   168  			updateErr = ErrUnknownPaymentStatus
   169  			return nil
   170  		}
   171  
   172  		// Before we set our new sequence number, we check whether this
   173  		// payment has a previously set sequence number and remove its
   174  		// index entry if it exists. This happens in the case where we
   175  		// have a previously attempted payment which was left in a state
   176  		// where we can retry.
   177  		seqBytes := bucket.Get(paymentSequenceKey)
   178  		if seqBytes != nil {
   179  			indexBucket := tx.ReadWriteBucket(paymentsIndexBucket)
   180  			if err := indexBucket.Delete(seqBytes); err != nil {
   181  				return err
   182  			}
   183  		}
   184  
   185  		// Once we have obtained a sequence number, we add an entry
   186  		// to our index bucket which will map the sequence number to
   187  		// our payment identifier.
   188  		err = createPaymentIndexEntry(
   189  			tx, sequenceNum, info.PaymentIdentifier,
   190  		)
   191  		if err != nil {
   192  			return err
   193  		}
   194  
   195  		err = bucket.Put(paymentSequenceKey, sequenceNum)
   196  		if err != nil {
   197  			return err
   198  		}
   199  
   200  		// Add the payment info to the bucket, which contains the
   201  		// static information for this payment
   202  		err = bucket.Put(paymentCreationInfoKey, infoBytes)
   203  		if err != nil {
   204  			return err
   205  		}
   206  
   207  		// We'll delete any lingering HTLCs to start with, in case we
   208  		// are initializing a payment that was attempted earlier, but
   209  		// left in a state where we could retry.
   210  		err = bucket.DeleteNestedBucket(paymentHtlcsBucket)
   211  		if err != nil && err != kvdb.ErrBucketNotFound {
   212  			return err
   213  		}
   214  
   215  		// Mark payment as inflight in the inflight payments index.
   216  		err = createPaymentInflightIndexEntry(tx, sequenceNum)
   217  		if err != nil {
   218  			return err
   219  		}
   220  
   221  		// Also delete any lingering failure info now that we are
   222  		// re-attempting.
   223  		return bucket.Delete(paymentFailInfoKey)
   224  	})
   225  	if err != nil {
   226  		return err
   227  	}
   228  
   229  	return updateErr
   230  }
   231  
   232  // paymentIndexTypeHash is a payment index type which indicates that we have
   233  // created an index of payment sequence number to payment hash.
   234  type paymentIndexType uint8
   235  
   236  // paymentIndexTypeHash is a payment index type which indicates that we have
   237  // created an index of payment sequence number to payment hash.
   238  const paymentIndexTypeHash paymentIndexType = 0
   239  
   240  // createPaymentIndexEntry creates a payment hash typed index for a payment. The
   241  // index produced contains a payment index type (which can be used in future to
   242  // signal different payment index types) and the payment identifier.
   243  func createPaymentIndexEntry(tx kvdb.RwTx, sequenceNumber []byte,
   244  	id lntypes.Hash) error {
   245  
   246  	var b bytes.Buffer
   247  	if err := WriteElements(&b, paymentIndexTypeHash, id[:]); err != nil {
   248  		return err
   249  	}
   250  
   251  	indexes := tx.ReadWriteBucket(paymentsIndexBucket)
   252  	return indexes.Put(sequenceNumber, b.Bytes())
   253  }
   254  
   255  // deserializePaymentIndex deserializes a payment index entry. This function
   256  // currently only supports deserialization of payment hash indexes, and will
   257  // fail for other types.
   258  func deserializePaymentIndex(r io.Reader) (lntypes.Hash, error) {
   259  	var (
   260  		indexType   paymentIndexType
   261  		paymentHash []byte
   262  	)
   263  
   264  	if err := ReadElements(r, &indexType, &paymentHash); err != nil {
   265  		return lntypes.Hash{}, err
   266  	}
   267  
   268  	// While we only have on payment index type, we do not need to use our
   269  	// index type to deserialize the index. However, we sanity check that
   270  	// this type is as expected, since we had to read it out anyway.
   271  	if indexType != paymentIndexTypeHash {
   272  		return lntypes.Hash{}, fmt.Errorf("unknown payment index "+
   273  			"type: %v", indexType)
   274  	}
   275  
   276  	hash, err := lntypes.MakeHash(paymentHash)
   277  	if err != nil {
   278  		return lntypes.Hash{}, err
   279  	}
   280  
   281  	return hash, nil
   282  }
   283  
   284  // RegisterAttempt atomically records the provided HTLCAttemptInfo to the
   285  // DB.
   286  func (p *PaymentControl) RegisterAttempt(paymentHash lntypes.Hash,
   287  	attempt *HTLCAttemptInfo) (*MPPayment, error) {
   288  
   289  	// Serialize the information before opening the db transaction.
   290  	var a bytes.Buffer
   291  	err := serializeHTLCAttemptInfo(&a, attempt)
   292  	if err != nil {
   293  		return nil, err
   294  	}
   295  	htlcInfoBytes := a.Bytes()
   296  
   297  	htlcIDBytes := make([]byte, 8)
   298  	binary.BigEndian.PutUint64(htlcIDBytes, attempt.AttemptID)
   299  
   300  	var payment *MPPayment
   301  	err = kvdb.Batch(p.db.Backend, func(tx kvdb.RwTx) error {
   302  		prefetchPayment(tx, paymentHash)
   303  		bucket, err := fetchPaymentBucketUpdate(tx, paymentHash)
   304  		if err != nil {
   305  			return err
   306  		}
   307  
   308  		p, err := fetchPayment(bucket)
   309  		if err != nil {
   310  			return err
   311  		}
   312  
   313  		// We cannot register a new attempt if the payment already has
   314  		// reached a terminal condition. We check this before
   315  		// ensureInFlight because it is a more general check.
   316  		settle, fail := p.TerminalInfo()
   317  		if settle != nil || fail != nil {
   318  			return ErrPaymentTerminal
   319  		}
   320  
   321  		// Ensure the payment is in-flight.
   322  		if err := ensureInFlight(p); err != nil {
   323  			return err
   324  		}
   325  
   326  		// Make sure any existing shards match the new one with regards
   327  		// to MPP options.
   328  		mpp := attempt.Route.FinalHop().MPP
   329  		for _, h := range p.InFlightHTLCs() {
   330  			hMpp := h.Route.FinalHop().MPP
   331  
   332  			switch {
   333  
   334  			// We tried to register a non-MPP attempt for a MPP
   335  			// payment.
   336  			case mpp == nil && hMpp != nil:
   337  				return ErrMPPayment
   338  
   339  			// We tried to register a MPP shard for a non-MPP
   340  			// payment.
   341  			case mpp != nil && hMpp == nil:
   342  				return ErrNonMPPayment
   343  
   344  			// Non-MPP payment, nothing more to validate.
   345  			case mpp == nil:
   346  				continue
   347  			}
   348  
   349  			// Check that MPP options match.
   350  			if mpp.PaymentAddr() != hMpp.PaymentAddr() {
   351  				return ErrMPPPaymentAddrMismatch
   352  			}
   353  
   354  			if mpp.TotalMAtoms() != hMpp.TotalMAtoms() {
   355  				return ErrMPPTotalAmountMismatch
   356  			}
   357  		}
   358  
   359  		// If this is a non-MPP attempt, it must match the total amount
   360  		// exactly.
   361  		amt := attempt.Route.ReceiverAmt()
   362  		if mpp == nil && amt != p.Info.Value {
   363  			return ErrValueMismatch
   364  		}
   365  
   366  		// Ensure we aren't sending more than the total payment amount.
   367  		sentAmt, _ := p.SentAmt()
   368  		if sentAmt+amt > p.Info.Value {
   369  			return ErrValueExceedsAmt
   370  		}
   371  
   372  		htlcsBucket, err := bucket.CreateBucketIfNotExists(
   373  			paymentHtlcsBucket,
   374  		)
   375  		if err != nil {
   376  			return err
   377  		}
   378  
   379  		err = htlcsBucket.Put(
   380  			htlcBucketKey(htlcAttemptInfoKey, htlcIDBytes),
   381  			htlcInfoBytes,
   382  		)
   383  		if err != nil {
   384  			return err
   385  		}
   386  
   387  		// Retrieve attempt info for the notification.
   388  		payment, err = fetchPayment(bucket)
   389  		if err != nil {
   390  			return err
   391  		}
   392  
   393  		err = updatePaymentInflightIndexEntry(tx, payment)
   394  		return err
   395  	})
   396  	if err != nil {
   397  		return nil, err
   398  	}
   399  
   400  	return payment, err
   401  }
   402  
   403  // SettleAttempt marks the given attempt settled with the preimage. If this is
   404  // a multi shard payment, this might implicitly mean that the full payment
   405  // succeeded.
   406  //
   407  // After invoking this method, InitPayment should always return an error to
   408  // prevent us from making duplicate payments to the same payment hash. The
   409  // provided preimage is atomically saved to the DB for record keeping.
   410  func (p *PaymentControl) SettleAttempt(hash lntypes.Hash,
   411  	attemptID uint64, settleInfo *HTLCSettleInfo) (*MPPayment, error) {
   412  
   413  	var b bytes.Buffer
   414  	if err := serializeHTLCSettleInfo(&b, settleInfo); err != nil {
   415  		return nil, err
   416  	}
   417  	settleBytes := b.Bytes()
   418  
   419  	return p.updateHtlcKey(hash, attemptID, htlcSettleInfoKey, settleBytes)
   420  }
   421  
   422  // FailAttempt marks the given payment attempt failed.
   423  func (p *PaymentControl) FailAttempt(hash lntypes.Hash,
   424  	attemptID uint64, failInfo *HTLCFailInfo) (*MPPayment, error) {
   425  
   426  	var b bytes.Buffer
   427  	if err := serializeHTLCFailInfo(&b, failInfo); err != nil {
   428  		return nil, err
   429  	}
   430  	failBytes := b.Bytes()
   431  
   432  	return p.updateHtlcKey(hash, attemptID, htlcFailInfoKey, failBytes)
   433  }
   434  
   435  // updateHtlcKey updates a database key for the specified htlc.
   436  func (p *PaymentControl) updateHtlcKey(paymentHash lntypes.Hash,
   437  	attemptID uint64, key, value []byte) (*MPPayment, error) {
   438  
   439  	aid := make([]byte, 8)
   440  	binary.BigEndian.PutUint64(aid, attemptID)
   441  
   442  	var payment *MPPayment
   443  	err := kvdb.Batch(p.db.Backend, func(tx kvdb.RwTx) error {
   444  		payment = nil
   445  
   446  		prefetchPayment(tx, paymentHash)
   447  		bucket, err := fetchPaymentBucketUpdate(tx, paymentHash)
   448  		if err != nil {
   449  			return err
   450  		}
   451  
   452  		p, err := fetchPayment(bucket)
   453  		if err != nil {
   454  			return err
   455  		}
   456  
   457  		// We can only update keys of in-flight payments. We allow
   458  		// updating keys even if the payment has reached a terminal
   459  		// condition, since the HTLC outcomes must still be updated.
   460  		if err := ensureInFlight(p); err != nil {
   461  			return err
   462  		}
   463  
   464  		htlcsBucket := bucket.NestedReadWriteBucket(paymentHtlcsBucket)
   465  		if htlcsBucket == nil {
   466  			return fmt.Errorf("htlcs bucket not found")
   467  		}
   468  
   469  		if htlcsBucket.Get(htlcBucketKey(htlcAttemptInfoKey, aid)) == nil {
   470  			return fmt.Errorf("HTLC with ID %v not registered",
   471  				attemptID)
   472  		}
   473  
   474  		// Make sure the shard is not already failed or settled.
   475  		if htlcsBucket.Get(htlcBucketKey(htlcFailInfoKey, aid)) != nil {
   476  			return ErrAttemptAlreadyFailed
   477  		}
   478  
   479  		if htlcsBucket.Get(htlcBucketKey(htlcSettleInfoKey, aid)) != nil {
   480  			return ErrAttemptAlreadySettled
   481  		}
   482  
   483  		// Add or update the key for this htlc.
   484  		err = htlcsBucket.Put(htlcBucketKey(key, aid), value)
   485  		if err != nil {
   486  			return err
   487  		}
   488  
   489  		// Retrieve attempt info for the notification.
   490  		payment, err = fetchPayment(bucket)
   491  		if err != nil {
   492  			return err
   493  		}
   494  
   495  		err = updatePaymentInflightIndexEntry(tx, payment)
   496  		return err
   497  	})
   498  	if err != nil {
   499  		return nil, err
   500  	}
   501  
   502  	return payment, err
   503  }
   504  
   505  // Fail transitions a payment into the Failed state, and records the reason the
   506  // payment failed. After invoking this method, InitPayment should return nil on
   507  // its next call for this payment hash, allowing the switch to make a
   508  // subsequent payment.
   509  func (p *PaymentControl) Fail(paymentHash lntypes.Hash,
   510  	reason FailureReason) (*MPPayment, error) {
   511  
   512  	var (
   513  		updateErr error
   514  		payment   *MPPayment
   515  	)
   516  	err := kvdb.Batch(p.db.Backend, func(tx kvdb.RwTx) error {
   517  		// Reset the update error, to avoid carrying over an error
   518  		// from a previous execution of the batched db transaction.
   519  		updateErr = nil
   520  		payment = nil
   521  
   522  		prefetchPayment(tx, paymentHash)
   523  		bucket, err := fetchPaymentBucketUpdate(tx, paymentHash)
   524  		if err == ErrPaymentNotInitiated {
   525  			updateErr = ErrPaymentNotInitiated
   526  			return nil
   527  		} else if err != nil {
   528  			return err
   529  		}
   530  
   531  		// We mark the payment as failed as long as it is known. This
   532  		// lets the last attempt to fail with a terminal write its
   533  		// failure to the PaymentControl without synchronizing with
   534  		// other attempts.
   535  		paymentStatus, err := fetchPaymentStatus(bucket)
   536  		if err != nil {
   537  			return err
   538  		}
   539  
   540  		if paymentStatus == StatusUnknown {
   541  			updateErr = ErrPaymentNotInitiated
   542  			return nil
   543  		}
   544  
   545  		// Put the failure reason in the bucket for record keeping.
   546  		v := []byte{byte(reason)}
   547  		err = bucket.Put(paymentFailInfoKey, v)
   548  		if err != nil {
   549  			return err
   550  		}
   551  
   552  		// Retrieve attempt info for the notification, if available.
   553  		payment, err = fetchPayment(bucket)
   554  		if err != nil {
   555  			return err
   556  		}
   557  
   558  		err = updatePaymentInflightIndexEntry(tx, payment)
   559  		return err
   560  	})
   561  	if err != nil {
   562  		return nil, err
   563  	}
   564  
   565  	return payment, updateErr
   566  }
   567  
   568  // FetchPayment returns information about a payment from the database.
   569  func (p *PaymentControl) FetchPayment(paymentHash lntypes.Hash) (
   570  	*MPPayment, error) {
   571  
   572  	var payment *MPPayment
   573  	err := kvdb.View(p.db, func(tx kvdb.RTx) error {
   574  		prefetchPayment(tx, paymentHash)
   575  		bucket, err := fetchPaymentBucket(tx, paymentHash)
   576  		if err != nil {
   577  			return err
   578  		}
   579  
   580  		payment, err = fetchPayment(bucket)
   581  
   582  		return err
   583  	}, func() {
   584  		payment = nil
   585  	})
   586  	if err != nil {
   587  		return nil, err
   588  	}
   589  
   590  	return payment, nil
   591  }
   592  
   593  // prefetchPayment attempts to prefetch as much of the payment as possible to
   594  // reduce DB roundtrips.
   595  func prefetchPayment(tx kvdb.RTx, paymentHash lntypes.Hash) {
   596  	rb := kvdb.RootBucket(tx)
   597  	kvdb.Prefetch(
   598  		rb,
   599  		[]string{
   600  			// Prefetch all keys in the payment's bucket.
   601  			string(paymentsRootBucket),
   602  			string(paymentHash[:]),
   603  		},
   604  		[]string{
   605  			// Prefetch all keys in the payment's htlc bucket.
   606  			string(paymentsRootBucket),
   607  			string(paymentHash[:]),
   608  			string(paymentHtlcsBucket),
   609  		},
   610  	)
   611  }
   612  
   613  // createPaymentBucket creates or fetches the sub-bucket assigned to this
   614  // payment hash.
   615  func createPaymentBucket(tx kvdb.RwTx, paymentHash lntypes.Hash) (
   616  	kvdb.RwBucket, error) {
   617  
   618  	payments, err := tx.CreateTopLevelBucket(paymentsRootBucket)
   619  	if err != nil {
   620  		return nil, err
   621  	}
   622  
   623  	return payments.CreateBucketIfNotExists(paymentHash[:])
   624  }
   625  
   626  // fetchPaymentBucket fetches the sub-bucket assigned to this payment hash. If
   627  // the bucket does not exist, it returns ErrPaymentNotInitiated.
   628  func fetchPaymentBucket(tx kvdb.RTx, paymentHash lntypes.Hash) (
   629  	kvdb.RBucket, error) {
   630  
   631  	payments := tx.ReadBucket(paymentsRootBucket)
   632  	if payments == nil {
   633  		return nil, ErrPaymentNotInitiated
   634  	}
   635  
   636  	bucket := payments.NestedReadBucket(paymentHash[:])
   637  	if bucket == nil {
   638  		return nil, ErrPaymentNotInitiated
   639  	}
   640  
   641  	return bucket, nil
   642  
   643  }
   644  
   645  // fetchPaymentBucketUpdate is identical to fetchPaymentBucket, but it returns a
   646  // bucket that can be written to.
   647  func fetchPaymentBucketUpdate(tx kvdb.RwTx, paymentHash lntypes.Hash) (
   648  	kvdb.RwBucket, error) {
   649  
   650  	payments := tx.ReadWriteBucket(paymentsRootBucket)
   651  	if payments == nil {
   652  		return nil, ErrPaymentNotInitiated
   653  	}
   654  
   655  	bucket := payments.NestedReadWriteBucket(paymentHash[:])
   656  	if bucket == nil {
   657  		return nil, ErrPaymentNotInitiated
   658  	}
   659  
   660  	return bucket, nil
   661  }
   662  
   663  // nextPaymentSequence returns the next sequence number to store for a new
   664  // payment.
   665  func (p *PaymentControl) nextPaymentSequence() ([]byte, error) {
   666  	p.paymentSeqMx.Lock()
   667  	defer p.paymentSeqMx.Unlock()
   668  
   669  	// Set a new upper bound in the DB every 1000 payments to avoid
   670  	// conflicts on the sequence when using etcd.
   671  	if p.currPaymentSeq == p.storedPaymentSeq {
   672  		var currPaymentSeq, newUpperBound uint64
   673  		if err := kvdb.Update(p.db.Backend, func(tx kvdb.RwTx) error {
   674  			paymentsBucket, err := tx.CreateTopLevelBucket(
   675  				paymentsRootBucket,
   676  			)
   677  			if err != nil {
   678  				return err
   679  			}
   680  
   681  			currPaymentSeq = paymentsBucket.Sequence()
   682  			newUpperBound = currPaymentSeq + paymentSeqBlockSize
   683  			return paymentsBucket.SetSequence(newUpperBound)
   684  		}, func() {}); err != nil {
   685  			return nil, err
   686  		}
   687  
   688  		// We lazy initialize the cached currPaymentSeq here using the
   689  		// first nextPaymentSequence() call. This if statement will auto
   690  		// initialize our stored currPaymentSeq, since by default both
   691  		// this variable and storedPaymentSeq are zero which in turn
   692  		// will have us fetch the current values from the DB.
   693  		if p.currPaymentSeq == 0 {
   694  			p.currPaymentSeq = currPaymentSeq
   695  		}
   696  
   697  		p.storedPaymentSeq = newUpperBound
   698  	}
   699  
   700  	p.currPaymentSeq++
   701  	b := make([]byte, 8)
   702  	binary.BigEndian.PutUint64(b, p.currPaymentSeq)
   703  
   704  	return b, nil
   705  }
   706  
   707  // fetchPaymentStatus fetches the payment status of the payment. If the payment
   708  // isn't found, it will default to "StatusUnknown".
   709  func fetchPaymentStatus(bucket kvdb.RBucket) (PaymentStatus, error) {
   710  	// Creation info should be set for all payments, regardless of state.
   711  	// If not, it is unknown.
   712  	if bucket.Get(paymentCreationInfoKey) == nil {
   713  		return StatusUnknown, nil
   714  	}
   715  
   716  	payment, err := fetchPayment(bucket)
   717  	if err != nil {
   718  		return 0, err
   719  	}
   720  
   721  	return payment.Status, nil
   722  }
   723  
   724  // ensureInFlight checks whether the payment found in the given bucket has
   725  // status InFlight, and returns an error otherwise. This should be used to
   726  // ensure we only mark in-flight payments as succeeded or failed.
   727  func ensureInFlight(payment *MPPayment) error {
   728  	paymentStatus := payment.Status
   729  
   730  	switch {
   731  
   732  	// The payment was indeed InFlight.
   733  	case paymentStatus == StatusInFlight:
   734  		return nil
   735  
   736  	// Our records show the payment as unknown, meaning it never
   737  	// should have left the switch.
   738  	case paymentStatus == StatusUnknown:
   739  		return ErrPaymentNotInitiated
   740  
   741  	// The payment succeeded previously.
   742  	case paymentStatus == StatusSucceeded:
   743  		return ErrPaymentAlreadySucceeded
   744  
   745  	// The payment was already failed.
   746  	case paymentStatus == StatusFailed:
   747  		return ErrPaymentAlreadyFailed
   748  
   749  	default:
   750  		return ErrUnknownPaymentStatus
   751  	}
   752  }
   753  
   754  // FetchInFlightPayments returns all payments with status InFlight.
   755  func (p *PaymentControl) FetchInFlightPayments() ([]*MPPayment, error) {
   756  	var inFlights []*MPPayment
   757  	err := kvdb.View(p.db, func(tx kvdb.RTx) error {
   758  		payments := tx.ReadBucket(paymentsRootBucket)
   759  		if payments == nil {
   760  			return nil
   761  		}
   762  
   763  		// Try to load the list of inflight payments by index. If the
   764  		// index does not exist (which is signalled by a specific error),
   765  		// continue attempting to list inflight payments
   766  		var err error
   767  		inFlights, err = fetchInflightPaymentsByIndex(tx)
   768  		if err == nil {
   769  			return nil
   770  		}
   771  		if err != nil && !errors.Is(err, errPaymentsInflightIndexNotExists) {
   772  			return err
   773  		}
   774  
   775  		return payments.ForEach(func(k, _ []byte) error {
   776  			bucket := payments.NestedReadBucket(k)
   777  			if bucket == nil {
   778  				return fmt.Errorf("non bucket element")
   779  			}
   780  
   781  			// If the status is not InFlight, we can return early.
   782  			paymentStatus, err := fetchPaymentStatus(bucket)
   783  			if err != nil {
   784  				return err
   785  			}
   786  
   787  			if paymentStatus != StatusInFlight {
   788  				return nil
   789  			}
   790  
   791  			p, err := fetchPayment(bucket)
   792  			if err != nil {
   793  				return err
   794  			}
   795  
   796  			inFlights = append(inFlights, p)
   797  			return nil
   798  		})
   799  	}, func() {
   800  		inFlights = nil
   801  	})
   802  	if err != nil {
   803  		return nil, err
   804  	}
   805  
   806  	return inFlights, nil
   807  }