• 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.57
/witness_beacon.go
1
package lnd
2

3
import (
4
        "errors"
5
        "sync"
6

7
        "github.com/lightningnetwork/lnd/channeldb"
8
        "github.com/lightningnetwork/lnd/contractcourt"
9
        "github.com/lightningnetwork/lnd/graph/db/models"
10
        "github.com/lightningnetwork/lnd/htlcswitch"
11
        "github.com/lightningnetwork/lnd/htlcswitch/hop"
12
        "github.com/lightningnetwork/lnd/lntypes"
13
        "github.com/lightningnetwork/lnd/lnwire"
14
)
15

16
// preimageSubscriber reprints an active subscription to be notified once the
17
// daemon discovers new preimages, either on chain or off-chain.
18
type preimageSubscriber struct {
19
        updateChan chan lntypes.Preimage
20

21
        quit chan struct{}
22
}
23

24
type witnessCache interface {
25
        // LookupSha256Witness attempts to lookup the preimage for a sha256
26
        // hash. If the witness isn't found, ErrNoWitnesses will be returned.
27
        LookupSha256Witness(hash lntypes.Hash) (lntypes.Preimage, error)
28

29
        // AddSha256Witnesses adds a batch of new sha256 preimages into the
30
        // witness cache. This is an alias for AddWitnesses that uses
31
        // Sha256HashWitness as the preimages' witness type.
32
        AddSha256Witnesses(preimages ...lntypes.Preimage) error
33
}
34

35
// preimageBeacon is an implementation of the contractcourt.WitnessBeacon
36
// interface, and the lnwallet.PreimageCache interface. This implementation is
37
// concerned with a single witness type: sha256 hahsh preimages.
38
type preimageBeacon struct {
39
        sync.RWMutex
40

41
        wCache witnessCache
42

43
        clientCounter uint64
44
        subscribers   map[uint64]*preimageSubscriber
45

46
        interceptor func(htlcswitch.InterceptedForward) error
47
}
48

49
func newPreimageBeacon(wCache witnessCache,
50
        interceptor func(htlcswitch.InterceptedForward) error) *preimageBeacon {
1✔
51

1✔
52
        return &preimageBeacon{
1✔
53
                wCache:      wCache,
1✔
54
                interceptor: interceptor,
1✔
55
                subscribers: make(map[uint64]*preimageSubscriber),
1✔
56
        }
1✔
57
}
1✔
58

59
// SubscribeUpdates returns a channel that will be sent upon *each* time a new
60
// preimage is discovered.
61
func (p *preimageBeacon) SubscribeUpdates(
62
        chanID lnwire.ShortChannelID, htlc *channeldb.HTLC,
63
        payload *hop.Payload,
64
        nextHopOnionBlob []byte) (*contractcourt.WitnessSubscription, error) {
1✔
65

1✔
66
        p.Lock()
1✔
67
        defer p.Unlock()
1✔
68

1✔
69
        clientID := p.clientCounter
1✔
70
        client := &preimageSubscriber{
1✔
71
                updateChan: make(chan lntypes.Preimage, 10),
1✔
72
                quit:       make(chan struct{}),
1✔
73
        }
1✔
74

1✔
75
        p.subscribers[p.clientCounter] = client
1✔
76

1✔
77
        p.clientCounter++
1✔
78

1✔
79
        srvrLog.Debugf("Creating new witness beacon subscriber, id=%v",
1✔
80
                p.clientCounter)
1✔
81

1✔
82
        sub := &contractcourt.WitnessSubscription{
1✔
83
                WitnessUpdates: client.updateChan,
1✔
84
                CancelSubscription: func() {
2✔
85
                        p.Lock()
1✔
86
                        defer p.Unlock()
1✔
87

1✔
88
                        delete(p.subscribers, clientID)
1✔
89

1✔
90
                        close(client.quit)
1✔
91
                },
1✔
92
        }
93

94
        // Notify the htlc interceptor. There may be a client connected
95
        // and willing to supply a preimage.
96
        packet := &htlcswitch.InterceptedPacket{
1✔
97
                Hash:           htlc.RHash,
1✔
98
                IncomingExpiry: htlc.RefundTimeout,
1✔
99
                IncomingAmount: htlc.Amt,
1✔
100
                IncomingCircuit: models.CircuitKey{
1✔
101
                        ChanID: chanID,
1✔
102
                        HtlcID: htlc.HtlcIndex,
1✔
103
                },
1✔
104
                OutgoingChanID:       payload.FwdInfo.NextHop,
1✔
105
                OutgoingExpiry:       payload.FwdInfo.OutgoingCTLV,
1✔
106
                OutgoingAmount:       payload.FwdInfo.AmountToForward,
1✔
107
                InOnionCustomRecords: payload.CustomRecords(),
1✔
108
                InWireCustomRecords:  htlc.CustomRecords,
1✔
109
        }
1✔
110
        copy(packet.OnionBlob[:], nextHopOnionBlob)
1✔
111

1✔
112
        fwd := newInterceptedForward(packet, p)
1✔
113

1✔
114
        err := p.interceptor(fwd)
1✔
115
        if err != nil {
1✔
116
                return nil, err
×
117
        }
×
118

119
        return sub, nil
1✔
120
}
121

122
// LookupPreImage attempts to lookup a preimage in the global cache.  True is
123
// returned for the second argument if the preimage is found.
124
func (p *preimageBeacon) LookupPreimage(
125
        payHash lntypes.Hash) (lntypes.Preimage, bool) {
×
126

×
127
        p.RLock()
×
128
        defer p.RUnlock()
×
129

×
130
        // Otherwise, we'll perform a final check using the witness cache.
×
131
        preimage, err := p.wCache.LookupSha256Witness(payHash)
×
132
        if errors.Is(err, channeldb.ErrNoWitnesses) {
×
133
                ltndLog.Debugf("No witness for payment %v", payHash)
×
134
                return lntypes.Preimage{}, false
×
135
        }
×
136

137
        if err != nil {
×
138
                ltndLog.Errorf("Unable to lookup witness: %v", err)
×
139
                return lntypes.Preimage{}, false
×
140
        }
×
141

142
        return preimage, true
×
143
}
144

145
// AddPreimages adds a batch of newly discovered preimages to the global cache,
146
// and also signals any subscribers of the newly discovered witness.
147
func (p *preimageBeacon) AddPreimages(preimages ...lntypes.Preimage) error {
1✔
148
        // Exit early if no preimages are presented.
1✔
149
        if len(preimages) == 0 {
1✔
150
                return nil
×
151
        }
×
152

153
        // Copy the preimages to ensure the backing area can't be modified by
154
        // the caller when delivering notifications.
155
        preimageCopies := make([]lntypes.Preimage, 0, len(preimages))
1✔
156
        for _, preimage := range preimages {
2✔
157
                srvrLog.Infof("Adding preimage=%v to witness cache for %v",
1✔
158
                        preimage, preimage.Hash())
1✔
159

1✔
160
                preimageCopies = append(preimageCopies, preimage)
1✔
161
        }
1✔
162

163
        // First, we'll add the witness to the decaying witness cache.
164
        err := p.wCache.AddSha256Witnesses(preimages...)
1✔
165
        if err != nil {
1✔
166
                return err
×
167
        }
×
168

169
        p.Lock()
1✔
170
        defer p.Unlock()
1✔
171

1✔
172
        // With the preimage added to our state, we'll now send a new
1✔
173
        // notification to all subscribers.
1✔
174
        for _, client := range p.subscribers {
2✔
175
                go func(c *preimageSubscriber) {
2✔
176
                        for _, preimage := range preimageCopies {
2✔
177
                                select {
1✔
178
                                case c.updateChan <- preimage:
1✔
179
                                case <-c.quit:
×
180
                                        return
×
181
                                }
182
                        }
183
                }(client)
184
        }
185

186
        srvrLog.Debugf("Added %d preimage(s) to witness cache",
1✔
187
                len(preimageCopies))
1✔
188

1✔
189
        return nil
1✔
190
}
191

192
var _ contractcourt.WitnessBeacon = (*preimageBeacon)(nil)
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