github.com/decred/dcrlnd@v0.7.6/channeldb/payments_stats.go (about) 1 package channeldb 2 3 import ( 4 "bytes" 5 6 "github.com/decred/dcrlnd/kvdb" 7 ) 8 9 // PaymentCountStats returns stats about the payments stored in the DB. 10 type PaymentCountStats struct { 11 Total uint64 12 Failed uint64 13 Succeeded uint64 14 15 HTLCAttempts uint64 16 HTLCFailed uint64 17 HTLCSettled uint64 18 19 OldDupePayments uint64 20 } 21 22 // CalcPaymentStats goes through the DB, counting up the payment stats. 23 func (d *DB) CalcPaymentStats() (*PaymentCountStats, error) { 24 res := &PaymentCountStats{} 25 err := kvdb.View(d, func(tx kvdb.RTx) error { 26 paymentsBucket := tx.ReadBucket(paymentsRootBucket) 27 if paymentsBucket == nil { 28 return nil 29 } 30 31 // Standard payments. 32 return paymentsBucket.ForEach(func(k, v []byte) error { 33 payBucket := paymentsBucket.NestedReadBucket(k) 34 if payBucket == nil { 35 return nil 36 } 37 38 res.Total += 1 39 40 htlcsBucket := payBucket.NestedReadBucket(paymentHtlcsBucket) 41 if htlcsBucket != nil { 42 var inflight, settled bool 43 err := htlcsBucket.ForEach(func(k, _ []byte) error { 44 if !bytes.HasPrefix(k, htlcAttemptInfoKey) { 45 return nil 46 } 47 ai := k[len(htlcAttemptInfoKey):] 48 res.HTLCAttempts += 1 49 hasFail := htlcsBucket.Get(htlcBucketKey(htlcFailInfoKey, ai)) != nil 50 hasSettle := htlcsBucket.Get(htlcBucketKey(htlcSettleInfoKey, ai)) != nil 51 if hasFail { 52 res.HTLCFailed += 1 53 } else if hasSettle { 54 res.HTLCSettled += 1 55 settled = true 56 } else { 57 inflight = true 58 } 59 return nil 60 }) 61 if err != nil { 62 return err 63 } 64 65 hasFailureReason := payBucket.Get(paymentFailInfoKey) != nil 66 67 switch { 68 // If any of the the HTLCs did succeed and there are no HTLCs in 69 // flight, the payment succeeded. 70 case !inflight && settled: 71 res.Succeeded += 1 72 73 // If we have no in-flight HTLCs, and the payment failure is set, the 74 // payment is considered failed. 75 case !inflight && hasFailureReason: 76 res.Failed += 1 77 } 78 79 } 80 81 // Old duplicate payments. 82 dupBucket := payBucket.NestedReadBucket(duplicatePaymentsBucket) 83 if dupBucket == nil { 84 return nil 85 } 86 87 return dupBucket.ForEach(func(k, v []byte) error { 88 subBucket := dupBucket.NestedReadBucket(k) 89 if subBucket == nil { 90 return nil 91 } 92 res.OldDupePayments += 1 93 return nil 94 }) 95 }) 96 }, func() {}) 97 98 return res, err 99 }