• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 13980275562

20 Mar 2025 10:06PM UTC coverage: 58.6% (-10.2%) from 68.789%
13980275562

Pull #9623

github

web-flow
Merge b9b960345 into 09b674508
Pull Request #9623: Size msg test msg

0 of 1518 new or added lines in 42 files covered. (0.0%)

26603 existing lines in 443 files now uncovered.

96807 of 165200 relevant lines covered (58.6%)

1.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

59.83
/channeldb/witness_cache.go
1
package channeldb
2

3
import (
4
        "fmt"
5

6
        "github.com/lightningnetwork/lnd/kvdb"
7
        "github.com/lightningnetwork/lnd/lntypes"
8
)
9

10
var (
11
        // ErrNoWitnesses is an error that's returned when no new witnesses have
12
        // been added to the WitnessCache.
13
        ErrNoWitnesses = fmt.Errorf("no witnesses")
14

15
        // ErrUnknownWitnessType is returned if a caller attempts to
16
        ErrUnknownWitnessType = fmt.Errorf("unknown witness type")
17
)
18

19
// WitnessType is enum that denotes what "type" of witness is being
20
// stored/retrieved. As the WitnessCache itself is agnostic and doesn't enforce
21
// any structure on added witnesses, we use this type to partition the
22
// witnesses on disk, and also to know how to map a witness to its look up key.
23
type WitnessType uint8
24

25
var (
26
        // Sha256HashWitness is a witness that is simply the pre image to a
27
        // hash image. In order to map to its key, we'll use sha256.
28
        Sha256HashWitness WitnessType = 1
29
)
30

31
// toDBKey is a helper method that maps a witness type to the key that we'll
32
// use to store it within the database.
33
func (w WitnessType) toDBKey() ([]byte, error) {
3✔
34
        switch w {
3✔
35

36
        case Sha256HashWitness:
3✔
37
                return []byte{byte(w)}, nil
3✔
38

39
        default:
×
40
                return nil, ErrUnknownWitnessType
×
41
        }
42
}
43

44
var (
45
        // witnessBucketKey is the name of the bucket that we use to store all
46
        // witnesses encountered. Within this bucket, we'll create a sub-bucket for
47
        // each witness type.
48
        witnessBucketKey = []byte("byte")
49
)
50

51
// WitnessCache is a persistent cache of all witnesses we've encountered on the
52
// network. In the case of multi-hop, multi-step contracts, a cache of all
53
// witnesses can be useful in the case of partial contract resolution. If
54
// negotiations break down, we may be forced to locate the witness for a
55
// portion of the contract on-chain. In this case, we'll then add that witness
56
// to the cache so the incoming contract can fully resolve witness.
57
// Additionally, as one MUST always use a unique witness on the network, we may
58
// use this cache to detect duplicate witnesses.
59
//
60
// TODO(roasbeef): need expiry policy?
61
//   - encrypt?
62
type WitnessCache struct {
63
        db *DB
64
}
65

66
// NewWitnessCache returns a new instance of the witness cache.
67
func (d *DB) NewWitnessCache() *WitnessCache {
3✔
68
        return &WitnessCache{
3✔
69
                db: d,
3✔
70
        }
3✔
71
}
3✔
72

73
// witnessEntry is a key-value struct that holds each key -> witness pair, used
74
// when inserting records into the cache.
75
type witnessEntry struct {
76
        key     []byte
77
        witness []byte
78
}
79

80
// AddSha256Witnesses adds a batch of new sha256 preimages into the witness
81
// cache. This is an alias for AddWitnesses that uses Sha256HashWitness as the
82
// preimages' witness type.
83
func (w *WitnessCache) AddSha256Witnesses(preimages ...lntypes.Preimage) error {
3✔
84
        // Optimistically compute the preimages' hashes before attempting to
3✔
85
        // start the db transaction.
3✔
86
        entries := make([]witnessEntry, 0, len(preimages))
3✔
87
        for i := range preimages {
6✔
88
                hash := preimages[i].Hash()
3✔
89
                entries = append(entries, witnessEntry{
3✔
90
                        key:     hash[:],
3✔
91
                        witness: preimages[i][:],
3✔
92
                })
3✔
93
        }
3✔
94

95
        return w.addWitnessEntries(Sha256HashWitness, entries)
3✔
96
}
97

98
// addWitnessEntries inserts the witnessEntry key-value pairs into the cache,
99
// using the appropriate witness type to segment the namespace of possible
100
// witness types.
101
func (w *WitnessCache) addWitnessEntries(wType WitnessType,
102
        entries []witnessEntry) error {
3✔
103

3✔
104
        // Exit early if there are no witnesses to add.
3✔
105
        if len(entries) == 0 {
3✔
106
                return nil
×
107
        }
×
108

109
        return kvdb.Batch(w.db.Backend, func(tx kvdb.RwTx) error {
6✔
110
                witnessBucket, err := tx.CreateTopLevelBucket(witnessBucketKey)
3✔
111
                if err != nil {
3✔
112
                        return err
×
113
                }
×
114

115
                witnessTypeBucketKey, err := wType.toDBKey()
3✔
116
                if err != nil {
3✔
117
                        return err
×
118
                }
×
119
                witnessTypeBucket, err := witnessBucket.CreateBucketIfNotExists(
3✔
120
                        witnessTypeBucketKey,
3✔
121
                )
3✔
122
                if err != nil {
3✔
123
                        return err
×
124
                }
×
125

126
                for _, entry := range entries {
6✔
127
                        err = witnessTypeBucket.Put(entry.key, entry.witness)
3✔
128
                        if err != nil {
3✔
129
                                return err
×
130
                        }
×
131
                }
132

133
                return nil
3✔
134
        })
135
}
136

137
// LookupSha256Witness attempts to lookup the preimage for a sha256 hash. If
138
// the witness isn't found, ErrNoWitnesses will be returned.
139
func (w *WitnessCache) LookupSha256Witness(hash lntypes.Hash) (lntypes.Preimage, error) {
3✔
140
        witness, err := w.lookupWitness(Sha256HashWitness, hash[:])
3✔
141
        if err != nil {
6✔
142
                return lntypes.Preimage{}, err
3✔
143
        }
3✔
144

145
        return lntypes.MakePreimage(witness)
3✔
146
}
147

148
// lookupWitness attempts to lookup a witness according to its type and also
149
// its witness key. In the case that the witness isn't found, ErrNoWitnesses
150
// will be returned.
151
func (w *WitnessCache) lookupWitness(wType WitnessType, witnessKey []byte) ([]byte, error) {
3✔
152
        var witness []byte
3✔
153
        err := kvdb.View(w.db, func(tx kvdb.RTx) error {
6✔
154
                witnessBucket := tx.ReadBucket(witnessBucketKey)
3✔
155
                if witnessBucket == nil {
6✔
156
                        return ErrNoWitnesses
3✔
157
                }
3✔
158

159
                witnessTypeBucketKey, err := wType.toDBKey()
3✔
160
                if err != nil {
3✔
161
                        return err
×
162
                }
×
163
                witnessTypeBucket := witnessBucket.NestedReadBucket(witnessTypeBucketKey)
3✔
164
                if witnessTypeBucket == nil {
3✔
UNCOV
165
                        return ErrNoWitnesses
×
UNCOV
166
                }
×
167

168
                dbWitness := witnessTypeBucket.Get(witnessKey)
3✔
169
                if dbWitness == nil {
6✔
170
                        return ErrNoWitnesses
3✔
171
                }
3✔
172

173
                witness = make([]byte, len(dbWitness))
3✔
174
                copy(witness[:], dbWitness)
3✔
175

3✔
176
                return nil
3✔
177
        }, func() {
3✔
178
                witness = nil
3✔
179
        })
3✔
180
        if err != nil {
6✔
181
                return nil, err
3✔
182
        }
3✔
183

184
        return witness, nil
3✔
185
}
186

187
// DeleteSha256Witness attempts to delete a sha256 preimage identified by hash.
UNCOV
188
func (w *WitnessCache) DeleteSha256Witness(hash lntypes.Hash) error {
×
UNCOV
189
        return w.deleteWitness(Sha256HashWitness, hash[:])
×
UNCOV
190
}
×
191

192
// deleteWitness attempts to delete a particular witness from the database.
UNCOV
193
func (w *WitnessCache) deleteWitness(wType WitnessType, witnessKey []byte) error {
×
UNCOV
194
        return kvdb.Batch(w.db.Backend, func(tx kvdb.RwTx) error {
×
UNCOV
195
                witnessBucket, err := tx.CreateTopLevelBucket(witnessBucketKey)
×
UNCOV
196
                if err != nil {
×
197
                        return err
×
198
                }
×
199

UNCOV
200
                witnessTypeBucketKey, err := wType.toDBKey()
×
UNCOV
201
                if err != nil {
×
202
                        return err
×
203
                }
×
UNCOV
204
                witnessTypeBucket, err := witnessBucket.CreateBucketIfNotExists(
×
UNCOV
205
                        witnessTypeBucketKey,
×
UNCOV
206
                )
×
UNCOV
207
                if err != nil {
×
208
                        return err
×
209
                }
×
210

UNCOV
211
                return witnessTypeBucket.Delete(witnessKey)
×
212
        })
213
}
214

215
// DeleteWitnessClass attempts to delete an *entire* class of witnesses. After
216
// this function return with a non-nil error,
UNCOV
217
func (w *WitnessCache) DeleteWitnessClass(wType WitnessType) error {
×
UNCOV
218
        return kvdb.Batch(w.db.Backend, func(tx kvdb.RwTx) error {
×
UNCOV
219
                witnessBucket, err := tx.CreateTopLevelBucket(witnessBucketKey)
×
UNCOV
220
                if err != nil {
×
221
                        return err
×
222
                }
×
223

UNCOV
224
                witnessTypeBucketKey, err := wType.toDBKey()
×
UNCOV
225
                if err != nil {
×
226
                        return err
×
227
                }
×
228

UNCOV
229
                return witnessBucket.DeleteNestedBucket(witnessTypeBucketKey)
×
230
        })
231
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc