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

lightningnetwork / lnd / 14193549836

01 Apr 2025 10:40AM UTC coverage: 69.046% (+0.007%) from 69.039%
14193549836

Pull #9665

github

web-flow
Merge e8825f209 into b01f4e514
Pull Request #9665: kvdb: bump etcd libs to v3.5.12

133439 of 193262 relevant lines covered (69.05%)

22119.45 hits per line

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

80.83
/htlcswitch/resolution_store.go
1
package htlcswitch
2

3
import (
4
        "bytes"
5
        "io"
6

7
        "github.com/go-errors/errors"
8
        "github.com/lightningnetwork/lnd/channeldb"
9
        "github.com/lightningnetwork/lnd/contractcourt"
10
        "github.com/lightningnetwork/lnd/kvdb"
11
        "github.com/lightningnetwork/lnd/lnwire"
12
)
13

14
var (
15
        // resBucketKey is used for the root level bucket that stores the
16
        // CircuitKey -> ResolutionMsg mapping.
17
        resBucketKey = []byte("resolution-store-bucket-key")
18

19
        // errResMsgNotFound is used to let callers know that the resolution
20
        // message was not found for the given CircuitKey. This is used in the
21
        // checkResolutionMsg function.
22
        errResMsgNotFound = errors.New("resolution message not found")
23
)
24

25
// resolutionStore contains ResolutionMsgs received from the contractcourt. The
26
// Switch deletes these from the store when the underlying circuit has been
27
// removed via DeleteCircuits. If the circuit hasn't been deleted, the Switch
28
// will dispatch the ResolutionMsg to a link if this was a multi-hop HTLC or to
29
// itself if the Switch initiated the payment.
30
type resolutionStore struct {
31
        backend kvdb.Backend
32
}
33

34
func newResolutionStore(db kvdb.Backend) *resolutionStore {
345✔
35
        return &resolutionStore{
345✔
36
                backend: db,
345✔
37
        }
345✔
38
}
345✔
39

40
// addResolutionMsg persists a ResolutionMsg to the resolutionStore.
41
func (r *resolutionStore) addResolutionMsg(
42
        resMsg *contractcourt.ResolutionMsg) error {
6✔
43

6✔
44
        // The outKey will be the database key.
6✔
45
        outKey := &CircuitKey{
6✔
46
                ChanID: resMsg.SourceChan,
6✔
47
                HtlcID: resMsg.HtlcIndex,
6✔
48
        }
6✔
49

6✔
50
        var resBuf bytes.Buffer
6✔
51
        if err := serializeResolutionMsg(&resBuf, resMsg); err != nil {
6✔
52
                return err
×
53
        }
×
54

55
        err := kvdb.Update(r.backend, func(tx kvdb.RwTx) error {
12✔
56
                resBucket, err := tx.CreateTopLevelBucket(resBucketKey)
6✔
57
                if err != nil {
6✔
58
                        return err
×
59
                }
×
60

61
                return resBucket.Put(outKey.Bytes(), resBuf.Bytes())
6✔
62
        }, func() {})
6✔
63
        if err != nil {
6✔
64
                return err
×
65
        }
×
66

67
        return nil
6✔
68
}
69

70
// checkResolutionMsg returns nil if the resolution message is found in the
71
// store. It returns an error if no resolution message was found for the
72
// passed outKey or if a database error occurred.
73
func (r *resolutionStore) checkResolutionMsg(outKey *CircuitKey) error {
7✔
74
        err := kvdb.View(r.backend, func(tx kvdb.RTx) error {
14✔
75
                resBucket := tx.ReadBucket(resBucketKey)
7✔
76
                if resBucket == nil {
7✔
77
                        // Return an error if the bucket doesn't exist.
×
78
                        return errResMsgNotFound
×
79
                }
×
80

81
                msg := resBucket.Get(outKey.Bytes())
7✔
82
                if msg == nil {
9✔
83
                        // Return the not found error since no message exists
2✔
84
                        // for this CircuitKey.
2✔
85
                        return errResMsgNotFound
2✔
86
                }
2✔
87

88
                // Return nil to indicate that the message was found.
89
                return nil
5✔
90
        }, func() {})
7✔
91
        if err != nil {
9✔
92
                return err
2✔
93
        }
2✔
94

95
        return nil
5✔
96
}
97

98
// fetchAllResolutionMsg returns a slice of all stored ResolutionMsgs. This is
99
// used by the Switch on start-up.
100
func (r *resolutionStore) fetchAllResolutionMsg() (
101
        []*contractcourt.ResolutionMsg, error) {
216✔
102

216✔
103
        var msgs []*contractcourt.ResolutionMsg
216✔
104

216✔
105
        err := kvdb.View(r.backend, func(tx kvdb.RTx) error {
432✔
106
                resBucket := tx.ReadBucket(resBucketKey)
216✔
107
                if resBucket == nil {
425✔
108
                        return nil
209✔
109
                }
209✔
110

111
                return resBucket.ForEach(func(k, v []byte) error {
19✔
112
                        kr := bytes.NewReader(k)
9✔
113
                        outKey := &CircuitKey{}
9✔
114
                        if err := outKey.Decode(kr); err != nil {
9✔
115
                                return err
×
116
                        }
×
117

118
                        vr := bytes.NewReader(v)
9✔
119
                        resMsg, err := deserializeResolutionMsg(vr)
9✔
120
                        if err != nil {
9✔
121
                                return err
×
122
                        }
×
123

124
                        // Set the CircuitKey values on the ResolutionMsg.
125
                        resMsg.SourceChan = outKey.ChanID
9✔
126
                        resMsg.HtlcIndex = outKey.HtlcID
9✔
127

9✔
128
                        msgs = append(msgs, resMsg)
9✔
129
                        return nil
9✔
130
                })
131
        }, func() {
216✔
132
                msgs = nil
216✔
133
        })
216✔
134
        if err != nil {
216✔
135
                return nil, err
×
136
        }
×
137

138
        return msgs, nil
216✔
139
}
140

141
// deleteResolutionMsg removes a ResolutionMsg with the passed-in CircuitKey.
142
func (r *resolutionStore) deleteResolutionMsg(outKey *CircuitKey) error {
6✔
143
        err := kvdb.Update(r.backend, func(tx kvdb.RwTx) error {
12✔
144
                resBucket, err := tx.CreateTopLevelBucket(resBucketKey)
6✔
145
                if err != nil {
6✔
146
                        return err
×
147
                }
×
148

149
                return resBucket.Delete(outKey.Bytes())
6✔
150
        }, func() {})
6✔
151
        return err
6✔
152
}
153

154
// serializeResolutionMsg writes part of a ResolutionMsg to the passed
155
// io.Writer.
156
func serializeResolutionMsg(w io.Writer,
157
        resMsg *contractcourt.ResolutionMsg) error {
6✔
158

6✔
159
        isFail := resMsg.Failure != nil
6✔
160

6✔
161
        if err := channeldb.WriteElement(w, isFail); err != nil {
6✔
162
                return err
×
163
        }
×
164

165
        // If this is a failure message, then we're done serializing.
166
        if isFail {
10✔
167
                return nil
4✔
168
        }
4✔
169

170
        // Else this is a settle message, and we need to write the preimage.
171
        return channeldb.WriteElement(w, *resMsg.PreImage)
5✔
172
}
173

174
// deserializeResolutionMsg reads part of a ResolutionMsg from the passed
175
// io.Reader.
176
func deserializeResolutionMsg(r io.Reader) (*contractcourt.ResolutionMsg,
177
        error) {
9✔
178

9✔
179
        resMsg := &contractcourt.ResolutionMsg{}
9✔
180
        var isFail bool
9✔
181

9✔
182
        if err := channeldb.ReadElements(r, &isFail); err != nil {
9✔
183
                return nil, err
×
184
        }
×
185

186
        // If a failure resolution msg was stored, set the Failure field.
187
        if isFail {
14✔
188
                failureMsg := &lnwire.FailPermanentChannelFailure{}
5✔
189
                resMsg.Failure = failureMsg
5✔
190
                return resMsg, nil
5✔
191
        }
5✔
192

193
        var preimage [32]byte
4✔
194
        resMsg.PreImage = &preimage
4✔
195

4✔
196
        // Else this is a settle resolution msg and we will read the preimage.
4✔
197
        if err := channeldb.ReadElement(r, resMsg.PreImage); err != nil {
4✔
198
                return nil, err
×
199
        }
×
200

201
        return resMsg, nil
4✔
202
}
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