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

lightningnetwork / lnd / 15561477203

10 Jun 2025 01:54PM UTC coverage: 58.351% (-10.1%) from 68.487%
15561477203

Pull #9356

github

web-flow
Merge 6440b25db into c6d6d4c0b
Pull Request #9356: lnrpc: add incoming/outgoing channel ids filter to forwarding history request

33 of 36 new or added lines in 2 files covered. (91.67%)

28366 existing lines in 455 files now uncovered.

97715 of 167461 relevant lines covered (58.35%)

1.81 hits per line

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

70.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 {
3✔
35
        return &resolutionStore{
3✔
36
                backend: db,
3✔
37
        }
3✔
38
}
3✔
39

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

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

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

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

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

67
        return nil
3✔
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 {
3✔
74
        err := kvdb.View(r.backend, func(tx kvdb.RTx) error {
6✔
75
                resBucket := tx.ReadBucket(resBucketKey)
3✔
76
                if resBucket == nil {
3✔
77
                        // Return an error if the bucket doesn't exist.
×
78
                        return errResMsgNotFound
×
79
                }
×
80

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

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

95
        return nil
3✔
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) {
3✔
102

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

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

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

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

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

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

138
        return msgs, nil
3✔
139
}
140

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

149
                return resBucket.Delete(outKey.Bytes())
3✔
150
        }, func() {})
3✔
151
        return err
3✔
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 {
3✔
158

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

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

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

170
        // Else this is a settle message, and we need to write the preimage.
171
        return channeldb.WriteElement(w, *resMsg.PreImage)
3✔
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) {
3✔
178

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

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

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

UNCOV
193
        var preimage [32]byte
×
UNCOV
194
        resMsg.PreImage = &preimage
×
UNCOV
195

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

UNCOV
201
        return resMsg, nil
×
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