mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-01-18 21:35:24 +01:00
channeldb: flatten the payment-htlcs-bucket
This commit is contained in:
parent
d50ee834e1
commit
63d7f5fca7
@ -368,14 +368,10 @@ func (p *PaymentControl) RegisterAttempt(paymentHash lntypes.Hash,
|
||||
return err
|
||||
}
|
||||
|
||||
// Create bucket for this attempt. Fail if the bucket already
|
||||
// exists.
|
||||
htlcBucket, err := htlcsBucket.CreateBucket(htlcIDBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = htlcBucket.Put(htlcAttemptInfoKey, htlcInfoBytes)
|
||||
err = htlcsBucket.Put(
|
||||
htlcBucketKey(htlcAttemptInfoKey, htlcIDBytes),
|
||||
htlcInfoBytes,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -427,8 +423,8 @@ func (p *PaymentControl) FailAttempt(hash lntypes.Hash,
|
||||
func (p *PaymentControl) updateHtlcKey(paymentHash lntypes.Hash,
|
||||
attemptID uint64, key, value []byte) (*MPPayment, error) {
|
||||
|
||||
htlcIDBytes := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(htlcIDBytes, attemptID)
|
||||
aid := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(aid, attemptID)
|
||||
|
||||
var payment *MPPayment
|
||||
err := kvdb.Batch(p.db.Backend, func(tx kvdb.RwTx) error {
|
||||
@ -456,23 +452,22 @@ func (p *PaymentControl) updateHtlcKey(paymentHash lntypes.Hash,
|
||||
return fmt.Errorf("htlcs bucket not found")
|
||||
}
|
||||
|
||||
htlcBucket := htlcsBucket.NestedReadWriteBucket(htlcIDBytes)
|
||||
if htlcBucket == nil {
|
||||
if htlcsBucket.Get(htlcBucketKey(htlcAttemptInfoKey, aid)) == nil {
|
||||
return fmt.Errorf("HTLC with ID %v not registered",
|
||||
attemptID)
|
||||
}
|
||||
|
||||
// Make sure the shard is not already failed or settled.
|
||||
if htlcBucket.Get(htlcFailInfoKey) != nil {
|
||||
if htlcsBucket.Get(htlcBucketKey(htlcFailInfoKey, aid)) != nil {
|
||||
return ErrAttemptAlreadyFailed
|
||||
}
|
||||
|
||||
if htlcBucket.Get(htlcSettleInfoKey) != nil {
|
||||
if htlcsBucket.Get(htlcBucketKey(htlcSettleInfoKey, aid)) != nil {
|
||||
return ErrAttemptAlreadySettled
|
||||
}
|
||||
|
||||
// Add or update the key for this htlc.
|
||||
err = htlcBucket.Put(key, value)
|
||||
err = htlcsBucket.Put(htlcBucketKey(key, aid), value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -35,14 +35,11 @@ var (
|
||||
// | |
|
||||
// | |--payment-htlcs-bucket (shard-bucket)
|
||||
// | | |
|
||||
// | | |-- <htlc attempt ID>
|
||||
// | | | |--htlc-attempt-info-key: <htlc attempt info>
|
||||
// | | | |--htlc-settle-info-key: <(optional) settle info>
|
||||
// | | | |--htlc-fail-info-key: <(optional) fail info>
|
||||
// | | |-- ai<htlc attempt ID>: <htlc attempt info>
|
||||
// | | |-- si<htlc attempt ID>: <(optional) settle info>
|
||||
// | | |-- fi<htlc attempt ID>: <(optional) fail info>
|
||||
// | | |
|
||||
// | | |-- <htlc attempt ID>
|
||||
// | | | |
|
||||
// | | ... ...
|
||||
// | | ...
|
||||
// | |
|
||||
// | |
|
||||
// | |--duplicate-bucket (only for old, completed payments)
|
||||
@ -50,9 +47,9 @@ var (
|
||||
// | |-- <seq-num>
|
||||
// | | |--sequence-key: <sequence number>
|
||||
// | | |--creation-info-key: <creation info>
|
||||
// | | |--attempt-info-key: <attempt info>
|
||||
// | | |--settle-info-key: <settle info>
|
||||
// | | |--fail-info-key: <fail info>
|
||||
// | | |--ai: <attempt info>
|
||||
// | | |--si: <settle info>
|
||||
// | | |--fi: <fail info>
|
||||
// | |
|
||||
// | |-- <seq-num>
|
||||
// | | |
|
||||
@ -77,17 +74,19 @@ var (
|
||||
// about the HTLCs that were attempted for a payment.
|
||||
paymentHtlcsBucket = []byte("payment-htlcs-bucket")
|
||||
|
||||
// htlcAttemptInfoKey is a key used in a HTLC's sub-bucket to store the
|
||||
// info about the attempt that was done for the HTLC in question.
|
||||
htlcAttemptInfoKey = []byte("htlc-attempt-info")
|
||||
// htlcAttemptInfoKey is the key used as the prefix of an HTLC attempt
|
||||
// to store the info about the attempt that was done for the HTLC in
|
||||
// question. The HTLC attempt ID is concatenated at the end.
|
||||
htlcAttemptInfoKey = []byte("ai")
|
||||
|
||||
// htlcSettleInfoKey is a key used in a HTLC's sub-bucket to store the
|
||||
// settle info, if any.
|
||||
htlcSettleInfoKey = []byte("htlc-settle-info")
|
||||
// htlcSettleInfoKey is the key used as the prefix of an HTLC attempt
|
||||
// settle info, if any. The HTLC attempt ID is concatenated at the end.
|
||||
htlcSettleInfoKey = []byte("si")
|
||||
|
||||
// htlcFailInfoKey is a key used in a HTLC's sub-bucket to store
|
||||
// failure information, if any.
|
||||
htlcFailInfoKey = []byte("htlc-fail-info")
|
||||
// htlcFailInfoKey is the key used as the prefix of an HTLC attempt
|
||||
// failure information, if any.The HTLC attempt ID is concatenated at
|
||||
// the end.
|
||||
htlcFailInfoKey = []byte("fi")
|
||||
|
||||
// paymentFailInfoKey is a key used in the payment's sub-bucket to
|
||||
// store information about the reason a payment failed.
|
||||
@ -230,6 +229,15 @@ type PaymentCreationInfo struct {
|
||||
PaymentRequest []byte
|
||||
}
|
||||
|
||||
// htlcBucketKey creates a composite key from prefix and id where the result is
|
||||
// simply the two concatenated.
|
||||
func htlcBucketKey(prefix, id []byte) []byte {
|
||||
key := make([]byte, len(prefix)+len(id))
|
||||
copy(key, prefix)
|
||||
copy(key[len(prefix):], id)
|
||||
return key
|
||||
}
|
||||
|
||||
// FetchPayments returns all sent payments found in the DB.
|
||||
//
|
||||
// nolint: dupl
|
||||
@ -378,80 +386,93 @@ func fetchPayment(bucket kvdb.RBucket) (*MPPayment, error) {
|
||||
// fetchHtlcAttempts retrives all htlc attempts made for the payment found in
|
||||
// the given bucket.
|
||||
func fetchHtlcAttempts(bucket kvdb.RBucket) ([]HTLCAttempt, error) {
|
||||
htlcs := make([]HTLCAttempt, 0)
|
||||
htlcsMap := make(map[uint64]*HTLCAttempt)
|
||||
|
||||
err := bucket.ForEach(func(k, _ []byte) error {
|
||||
aid := byteOrder.Uint64(k)
|
||||
htlcBucket := bucket.NestedReadBucket(k)
|
||||
attemptInfoCount := 0
|
||||
err := bucket.ForEach(func(k, v []byte) error {
|
||||
aid := byteOrder.Uint64(k[len(k)-8:])
|
||||
|
||||
attemptInfo, err := fetchHtlcAttemptInfo(
|
||||
htlcBucket,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attemptInfo.AttemptID = aid
|
||||
|
||||
htlc := HTLCAttempt{
|
||||
HTLCAttemptInfo: *attemptInfo,
|
||||
if _, ok := htlcsMap[aid]; !ok {
|
||||
htlcsMap[aid] = &HTLCAttempt{}
|
||||
}
|
||||
|
||||
// Settle info might be nil.
|
||||
htlc.Settle, err = fetchHtlcSettleInfo(htlcBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
var err error
|
||||
switch {
|
||||
case bytes.HasPrefix(k, htlcAttemptInfoKey):
|
||||
attemptInfo, err := readHtlcAttemptInfo(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
attemptInfo.AttemptID = aid
|
||||
htlcsMap[aid].HTLCAttemptInfo = *attemptInfo
|
||||
attemptInfoCount++
|
||||
|
||||
case bytes.HasPrefix(k, htlcSettleInfoKey):
|
||||
htlcsMap[aid].Settle, err = readHtlcSettleInfo(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case bytes.HasPrefix(k, htlcFailInfoKey):
|
||||
htlcsMap[aid].Failure, err = readHtlcFailInfo(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unknown htlc attempt key")
|
||||
}
|
||||
|
||||
// Failure info might be nil.
|
||||
htlc.Failure, err = fetchHtlcFailInfo(htlcBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
htlcs = append(htlcs, htlc)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return htlcs, nil
|
||||
}
|
||||
|
||||
// fetchHtlcAttemptInfo fetches the payment attempt info for this htlc from the
|
||||
// bucket.
|
||||
func fetchHtlcAttemptInfo(bucket kvdb.RBucket) (*HTLCAttemptInfo, error) {
|
||||
b := bucket.Get(htlcAttemptInfoKey)
|
||||
if b == nil {
|
||||
// Sanity check that all htlcs have an attempt info.
|
||||
if attemptInfoCount != len(htlcsMap) {
|
||||
return nil, errNoAttemptInfo
|
||||
}
|
||||
|
||||
keys := make([]uint64, len(htlcsMap))
|
||||
i := 0
|
||||
for k := range htlcsMap {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
|
||||
// Sort HTLC attempts by their attempt ID. This is needed because in the
|
||||
// DB we store the attempts with keys prefixed by their status which
|
||||
// changes order (groups them together by status).
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
return keys[i] < keys[j]
|
||||
})
|
||||
|
||||
htlcs := make([]HTLCAttempt, len(htlcsMap))
|
||||
for i, key := range keys {
|
||||
htlcs[i] = *htlcsMap[key]
|
||||
}
|
||||
|
||||
return htlcs, nil
|
||||
}
|
||||
|
||||
// readHtlcAttemptInfo reads the payment attempt info for this htlc.
|
||||
func readHtlcAttemptInfo(b []byte) (*HTLCAttemptInfo, error) {
|
||||
r := bytes.NewReader(b)
|
||||
return deserializeHTLCAttemptInfo(r)
|
||||
}
|
||||
|
||||
// fetchHtlcSettleInfo retrieves the settle info for the htlc. If the htlc isn't
|
||||
// readHtlcSettleInfo reads the settle info for the htlc. If the htlc isn't
|
||||
// settled, nil is returned.
|
||||
func fetchHtlcSettleInfo(bucket kvdb.RBucket) (*HTLCSettleInfo, error) {
|
||||
b := bucket.Get(htlcSettleInfoKey)
|
||||
if b == nil {
|
||||
// Settle info is optional.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func readHtlcSettleInfo(b []byte) (*HTLCSettleInfo, error) {
|
||||
r := bytes.NewReader(b)
|
||||
return deserializeHTLCSettleInfo(r)
|
||||
}
|
||||
|
||||
// fetchHtlcFailInfo retrieves the failure info for the htlc. If the htlc hasn't
|
||||
// readHtlcFailInfo reads the failure info for the htlc. If the htlc hasn't
|
||||
// failed, nil is returned.
|
||||
func fetchHtlcFailInfo(bucket kvdb.RBucket) (*HTLCFailInfo, error) {
|
||||
b := bucket.Get(htlcFailInfoKey)
|
||||
if b == nil {
|
||||
// Fail info is optional.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func readHtlcFailInfo(b []byte) (*HTLCFailInfo, error) {
|
||||
r := bytes.NewReader(b)
|
||||
return deserializeHTLCFailInfo(r)
|
||||
}
|
||||
@ -797,8 +818,21 @@ func (d *DB) DeletePayments(failedOnly, failedHtlcsOnly bool) error {
|
||||
)
|
||||
|
||||
for _, aid := range htlcIDs {
|
||||
err := htlcsBucket.DeleteNestedBucket(aid)
|
||||
if err != nil {
|
||||
if err := htlcsBucket.Delete(
|
||||
htlcBucketKey(htlcAttemptInfoKey, aid),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := htlcsBucket.Delete(
|
||||
htlcBucketKey(htlcFailInfoKey, aid),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := htlcsBucket.Delete(
|
||||
htlcBucketKey(htlcSettleInfoKey, aid),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user