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

lightningnetwork / lnd / 12312390362

13 Dec 2024 08:44AM UTC coverage: 57.458% (+8.5%) from 48.92%
12312390362

Pull #9343

github

ellemouton
fn: rework the ContextGuard and add tests

In this commit, the ContextGuard struct is re-worked such that the
context that its new main WithCtx method provides is cancelled in sync
with a parent context being cancelled or with it's quit channel being
cancelled. Tests are added to assert the behaviour. In order for the
close of the quit channel to be consistent with the cancelling of the
derived context, the quit channel _must_ be contained internal to the
ContextGuard so that callers are only able to close the channel via the
exposed Quit method which will then take care to first cancel any
derived context that depend on the quit channel before returning.
Pull Request #9343: fn: expand the ContextGuard and add tests

101853 of 177264 relevant lines covered (57.46%)

24972.93 hits per line

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

77.78
/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) {
17✔
34
        switch w {
17✔
35

36
        case Sha256HashWitness:
17✔
37
                return []byte{byte(w)}, nil
17✔
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 {
4✔
68
        return &WitnessCache{
4✔
69
                db: d,
4✔
70
        }
4✔
71
}
4✔
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 {
4✔
84
        // Optimistically compute the preimages' hashes before attempting to
4✔
85
        // start the db transaction.
4✔
86
        entries := make([]witnessEntry, 0, len(preimages))
4✔
87
        for i := range preimages {
10✔
88
                hash := preimages[i].Hash()
6✔
89
                entries = append(entries, witnessEntry{
6✔
90
                        key:     hash[:],
6✔
91
                        witness: preimages[i][:],
6✔
92
                })
6✔
93
        }
6✔
94

95
        return w.addWitnessEntries(Sha256HashWitness, entries)
4✔
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 {
5✔
103

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

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

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

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

133
                return nil
5✔
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) {
8✔
140
        witness, err := w.lookupWitness(Sha256HashWitness, hash[:])
8✔
141
        if err != nil {
10✔
142
                return lntypes.Preimage{}, err
2✔
143
        }
2✔
144

145
        return lntypes.MakePreimage(witness)
6✔
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) {
8✔
152
        var witness []byte
8✔
153
        err := kvdb.View(w.db, func(tx kvdb.RTx) error {
16✔
154
                witnessBucket := tx.ReadBucket(witnessBucketKey)
8✔
155
                if witnessBucket == nil {
8✔
156
                        return ErrNoWitnesses
×
157
                }
×
158

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

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

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

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

184
        return witness, nil
6✔
185
}
186

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

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

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

211
                return witnessTypeBucket.Delete(witnessKey)
3✔
212
        })
213
}
214

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

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

229
                return witnessBucket.DeleteNestedBucket(witnessTypeBucketKey)
1✔
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