From 7296cfb425ce6aa14320bb9291be4b370a2e56a3 Mon Sep 17 00:00:00 2001 From: Vadym Popov Date: Sun, 12 Aug 2018 16:12:37 +0300 Subject: [PATCH] channeldb: add payment statuses: ground, in flight, completed --- channeldb/payments.go | 96 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/channeldb/payments.go b/channeldb/payments.go index 0e5f47b9..aa880b0b 100644 --- a/channeldb/payments.go +++ b/channeldb/payments.go @@ -3,6 +3,7 @@ package channeldb import ( "bytes" "encoding/binary" + "errors" "io" "github.com/coreos/bbolt" @@ -17,8 +18,64 @@ var ( // which is a monotonically increasing uint64. BoltDB's sequence // feature is used for generating monotonically increasing id. paymentBucket = []byte("payments") + + // paymentStatusBucket is the name of the bucket within the database that + // stores the status of a payment indexed by the payment's preimage. + paymentStatusBucket = []byte("payment-status") ) +// PaymentStatus represent current status of payment +type PaymentStatus byte + +const ( + // StatusGrounded is status where payment is initiated and received + // an intermittent failure + StatusGrounded PaymentStatus = 0 + + // StatusInFlight is status where payment is initiated, but a response + // has not been received + StatusInFlight PaymentStatus = 1 + + // StatusCompleted is status where payment is initiated and complete + // a payment successfully + StatusCompleted PaymentStatus = 2 +) + +// Bytes returns status as slice of bytes +func (ps PaymentStatus) Bytes() []byte { + return []byte{byte(ps)} +} + +// FromBytes sets status from slice of bytes +func (ps *PaymentStatus) FromBytes(status []byte) error { + if len(status) != 1 { + return errors.New("payment status is empty") + } + + switch PaymentStatus(status[0]) { + case StatusGrounded, StatusInFlight, StatusCompleted: + *ps = PaymentStatus(status[0]) + default: + return errors.New("unknown payment status") + } + + return nil +} + +// String returns readable representation of payment status +func (ps PaymentStatus) String() string { + switch ps { + case StatusGrounded: + return "Grounded" + case StatusInFlight: + return "In Flight" + case StatusCompleted: + return "Completed" + default: + return "Unknown" + } +} + // OutgoingPayment represents a successful payment between the daemon and a // remote node. Details such as the total fee paid, and the time of the payment // are stored. @@ -129,6 +186,45 @@ func (db *DB) DeleteAllPayments() error { }) } +// UpdatePaymentStatus sets status for outgoing/finished payment to store status in +// local database. +func (db *DB) UpdatePaymentStatus(paymentHash [32]byte, status PaymentStatus) error { + return db.Batch(func(tx *bolt.Tx) error { + paymentStatuses, err := tx.CreateBucketIfNotExists(paymentStatusBucket) + if err != nil { + return err + } + + return paymentStatuses.Put(paymentHash[:], status.Bytes()) + }) +} + +// FetchPaymentStatus returns payment status for outgoing payment +// if status of the payment isn't found it set to default status "StatusGrounded". +func (db *DB) FetchPaymentStatus(paymentHash [32]byte) (PaymentStatus, error) { + // default status for all payments that wasn't recorded in database + paymentStatus := StatusGrounded + + err := db.View(func(tx *bolt.Tx) error { + bucket := tx.Bucket(paymentStatusBucket) + if bucket == nil { + return nil + } + + paymentStatusBytes := bucket.Get(paymentHash[:]) + if paymentStatusBytes == nil { + return nil + } + + return paymentStatus.FromBytes(paymentStatusBytes) + }) + if err != nil { + return StatusGrounded, err + } + + return paymentStatus, nil +} + func serializeOutgoingPayment(w io.Writer, p *OutgoingPayment) error { var scratch [8]byte