• 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

0.0
/channeldb/migration26/channel.go
1
package migration26
2

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

7
        lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
8
        mig25 "github.com/lightningnetwork/lnd/channeldb/migration25"
9
        mig "github.com/lightningnetwork/lnd/channeldb/migration_01_to_11"
10
        "github.com/lightningnetwork/lnd/kvdb"
11
        "github.com/lightningnetwork/lnd/tlv"
12
)
13

14
const (
15
        // A tlv type definition used to serialize and deserialize a KeyLocator
16
        // from the database.
17
        keyLocType tlv.Type = 1
18

19
        // A tlv type used to serialize and deserialize the
20
        // `InitialLocalBalance` field.
21
        initialLocalBalanceType tlv.Type = 2
22

23
        // A tlv type used to serialize and deserialize the
24
        // `InitialRemoteBalance` field.
25
        initialRemoteBalanceType tlv.Type = 3
26
)
27

28
var (
29
        // chanInfoKey can be accessed within the bucket for a channel
30
        // (identified by its chanPoint). This key stores all the static
31
        // information for a channel which is decided at the end of  the
32
        // funding flow.
33
        chanInfoKey = []byte("chan-info-key")
34

35
        // localUpfrontShutdownKey can be accessed within the bucket for a
36
        // channel (identified by its chanPoint). This key stores an optional
37
        // upfront shutdown script for the local peer.
38
        localUpfrontShutdownKey = []byte("local-upfront-shutdown-key")
39

40
        // remoteUpfrontShutdownKey can be accessed within the bucket for a
41
        // channel (identified by its chanPoint). This key stores an optional
42
        // upfront shutdown script for the remote peer.
43
        remoteUpfrontShutdownKey = []byte("remote-upfront-shutdown-key")
44

45
        // lastWasRevokeKey is a key that stores true when the last update we
46
        // sent was a revocation and false when it was a commitment signature.
47
        // This is nil in the case of new channels with no updates exchanged.
48
        lastWasRevokeKey = []byte("last-was-revoke")
49

50
        // ErrNoChanInfoFound is returned when a particular channel does not
51
        // have any channels state.
52
        ErrNoChanInfoFound = fmt.Errorf("no chan info found")
53

54
        // ErrNoPastDeltas is returned when the channel delta bucket hasn't been
55
        // created.
56
        ErrNoPastDeltas = fmt.Errorf("channel has no recorded deltas")
57

58
        // ErrLogEntryNotFound is returned when we cannot find a log entry at
59
        // the height requested in the revocation log.
60
        ErrLogEntryNotFound = fmt.Errorf("log entry not found")
61

62
        // ErrNoCommitmentsFound is returned when a channel has not set
63
        // commitment states.
64
        ErrNoCommitmentsFound = fmt.Errorf("no commitments found")
65
)
66

67
// OpenChannel embeds a mig25.OpenChannel with the extra update-to-date
68
// serialization and deserialization methods.
69
//
70
// NOTE: doesn't have the Packager field as it's not used in current migration.
71
type OpenChannel struct {
72
        mig25.OpenChannel
73
}
74

75
// FetchChanInfo deserializes the channel info based on the legacy boolean.
76
// After migration25, the legacy format would have the fields
77
// `InitialLocalBalance` and `InitialRemoteBalance` directly encoded as bytes.
78
// For the new format, they will be put inside a tlv stream.
UNCOV
79
func FetchChanInfo(chanBucket kvdb.RBucket, c *OpenChannel, legacy bool) error {
×
UNCOV
80
        infoBytes := chanBucket.Get(chanInfoKey)
×
UNCOV
81
        if infoBytes == nil {
×
82
                return ErrNoChanInfoFound
×
83
        }
×
UNCOV
84
        r := bytes.NewReader(infoBytes)
×
UNCOV
85

×
UNCOV
86
        var (
×
UNCOV
87
                chanType   mig.ChannelType
×
UNCOV
88
                chanStatus mig.ChannelStatus
×
UNCOV
89
        )
×
UNCOV
90

×
UNCOV
91
        if err := mig.ReadElements(r,
×
UNCOV
92
                &chanType, &c.ChainHash, &c.FundingOutpoint,
×
UNCOV
93
                &c.ShortChannelID, &c.IsPending, &c.IsInitiator,
×
UNCOV
94
                &chanStatus, &c.FundingBroadcastHeight,
×
UNCOV
95
                &c.NumConfsRequired, &c.ChannelFlags,
×
UNCOV
96
                &c.IdentityPub, &c.Capacity, &c.TotalMSatSent,
×
UNCOV
97
                &c.TotalMSatReceived,
×
UNCOV
98
        ); err != nil {
×
99
                return err
×
100
        }
×
101

UNCOV
102
        c.ChanType = mig25.ChannelType(chanType)
×
UNCOV
103
        c.ChanStatus = mig25.ChannelStatus(chanStatus)
×
UNCOV
104

×
UNCOV
105
        // If this is the legacy format, we need to read the extra two new
×
UNCOV
106
        // fields.
×
UNCOV
107
        if legacy {
×
UNCOV
108
                if err := mig.ReadElements(r,
×
UNCOV
109
                        &c.InitialLocalBalance, &c.InitialRemoteBalance,
×
UNCOV
110
                ); err != nil {
×
111
                        return err
×
112
                }
×
113
        }
114

115
        // For single funder channels that we initiated and have the funding
116
        // transaction to, read the funding txn.
UNCOV
117
        if c.FundingTxPresent() {
×
UNCOV
118
                if err := mig.ReadElement(r, &c.FundingTxn); err != nil {
×
119
                        return err
×
120
                }
×
121
        }
122

UNCOV
123
        if err := mig.ReadChanConfig(r, &c.LocalChanCfg); err != nil {
×
124
                return err
×
125
        }
×
UNCOV
126
        if err := mig.ReadChanConfig(r, &c.RemoteChanCfg); err != nil {
×
127
                return err
×
128
        }
×
129

130
        // Retrieve the boolean stored under lastWasRevokeKey.
UNCOV
131
        lastWasRevokeBytes := chanBucket.Get(lastWasRevokeKey)
×
UNCOV
132
        if lastWasRevokeBytes == nil {
×
UNCOV
133
                // If nothing has been stored under this key, we store false in
×
UNCOV
134
                // the OpenChannel struct.
×
UNCOV
135
                c.LastWasRevoke = false
×
UNCOV
136
        } else {
×
137
                // Otherwise, read the value into the LastWasRevoke field.
×
138
                revokeReader := bytes.NewReader(lastWasRevokeBytes)
×
139
                err := mig.ReadElements(revokeReader, &c.LastWasRevoke)
×
140
                if err != nil {
×
141
                        return err
×
142
                }
×
143
        }
144

145
        // Make the tlv stream based on the legacy param.
UNCOV
146
        var (
×
UNCOV
147
                ts            *tlv.Stream
×
UNCOV
148
                err           error
×
UNCOV
149
                localBalance  uint64
×
UNCOV
150
                remoteBalance uint64
×
UNCOV
151
        )
×
UNCOV
152

×
UNCOV
153
        keyLocRecord := mig25.MakeKeyLocRecord(
×
UNCOV
154
                keyLocType, &c.RevocationKeyLocator,
×
UNCOV
155
        )
×
UNCOV
156

×
UNCOV
157
        // If it's legacy, create the stream with a single tlv record.
×
UNCOV
158
        if legacy {
×
UNCOV
159
                ts, err = tlv.NewStream(keyLocRecord)
×
UNCOV
160
        } else {
×
UNCOV
161
                // Otherwise, for the new format, we will encode the balance
×
UNCOV
162
                // fields in the tlv stream too.
×
UNCOV
163
                ts, err = tlv.NewStream(
×
UNCOV
164
                        keyLocRecord,
×
UNCOV
165
                        tlv.MakePrimitiveRecord(
×
UNCOV
166
                                initialLocalBalanceType, &localBalance,
×
UNCOV
167
                        ),
×
UNCOV
168
                        tlv.MakePrimitiveRecord(
×
UNCOV
169
                                initialRemoteBalanceType, &remoteBalance,
×
UNCOV
170
                        ),
×
UNCOV
171
                )
×
UNCOV
172
        }
×
UNCOV
173
        if err != nil {
×
174
                return err
×
175
        }
×
176

UNCOV
177
        if err := ts.Decode(r); err != nil {
×
178
                return err
×
179
        }
×
180

181
        // For the new format, attach the balance fields.
UNCOV
182
        if !legacy {
×
UNCOV
183
                c.InitialLocalBalance = lnwire.MilliSatoshi(localBalance)
×
UNCOV
184
                c.InitialRemoteBalance = lnwire.MilliSatoshi(remoteBalance)
×
UNCOV
185
        }
×
186

187
        // Finally, read the optional shutdown scripts.
UNCOV
188
        if err := mig25.GetOptionalUpfrontShutdownScript(
×
UNCOV
189
                chanBucket, localUpfrontShutdownKey, &c.LocalShutdownScript,
×
UNCOV
190
        ); err != nil {
×
191
                return err
×
192
        }
×
193

UNCOV
194
        return mig25.GetOptionalUpfrontShutdownScript(
×
UNCOV
195
                chanBucket, remoteUpfrontShutdownKey, &c.RemoteShutdownScript,
×
UNCOV
196
        )
×
197
}
198

199
// MakeTlvStream creates a tlv stream based on whether we are deadling with
200
// legacy format or not. For the legacy format, we have a single record in the
201
// stream. For the new format, we have the extra balance records.
UNCOV
202
func MakeTlvStream(c *OpenChannel, legacy bool) (*tlv.Stream, error) {
×
UNCOV
203
        keyLocRecord := mig25.MakeKeyLocRecord(
×
UNCOV
204
                keyLocType, &c.RevocationKeyLocator,
×
UNCOV
205
        )
×
UNCOV
206

×
UNCOV
207
        // If it's legacy, return the stream with a single tlv record.
×
UNCOV
208
        if legacy {
×
UNCOV
209
                return tlv.NewStream(keyLocRecord)
×
UNCOV
210
        }
×
211

212
        // Otherwise, for the new format, we will encode the balance fields in
213
        // the tlv stream too.
UNCOV
214
        localBalance := uint64(c.InitialLocalBalance)
×
UNCOV
215
        remoteBalance := uint64(c.InitialRemoteBalance)
×
UNCOV
216

×
UNCOV
217
        // Create the tlv stream.
×
UNCOV
218
        return tlv.NewStream(
×
UNCOV
219
                keyLocRecord,
×
UNCOV
220
                tlv.MakePrimitiveRecord(
×
UNCOV
221
                        initialLocalBalanceType, &localBalance,
×
UNCOV
222
                ),
×
UNCOV
223
                tlv.MakePrimitiveRecord(
×
UNCOV
224
                        initialRemoteBalanceType, &remoteBalance,
×
UNCOV
225
                ),
×
UNCOV
226
        )
×
227
}
228

229
// PutChanInfo serializes the channel info based on the legacy boolean. After
230
// migration25, the legacy format would have the fields `InitialLocalBalance`
231
// and `InitialRemoteBalance` directly encoded as bytes. For the new format,
232
// they will be put inside a tlv stream.
UNCOV
233
func PutChanInfo(chanBucket kvdb.RwBucket, c *OpenChannel, legacy bool) error {
×
UNCOV
234
        var w bytes.Buffer
×
UNCOV
235
        if err := mig.WriteElements(&w,
×
UNCOV
236
                mig.ChannelType(c.ChanType), c.ChainHash, c.FundingOutpoint,
×
UNCOV
237
                c.ShortChannelID, c.IsPending, c.IsInitiator,
×
UNCOV
238
                mig.ChannelStatus(c.ChanStatus), c.FundingBroadcastHeight,
×
UNCOV
239
                c.NumConfsRequired, c.ChannelFlags,
×
UNCOV
240
                c.IdentityPub, c.Capacity, c.TotalMSatSent,
×
UNCOV
241
                c.TotalMSatReceived,
×
UNCOV
242
        ); err != nil {
×
243
                return err
×
244
        }
×
245

246
        // If this is legacy format, we need to write the extra two fields.
UNCOV
247
        if legacy {
×
UNCOV
248
                if err := mig.WriteElements(&w,
×
UNCOV
249
                        c.InitialLocalBalance, c.InitialRemoteBalance,
×
UNCOV
250
                ); err != nil {
×
251
                        return err
×
252
                }
×
253
        }
254

255
        // For single funder channels that we initiated, and we have the
256
        // funding transaction, then write the funding txn.
UNCOV
257
        if c.FundingTxPresent() {
×
UNCOV
258
                if err := mig.WriteElement(&w, c.FundingTxn); err != nil {
×
259
                        return err
×
260
                }
×
261
        }
262

UNCOV
263
        if err := mig.WriteChanConfig(&w, &c.LocalChanCfg); err != nil {
×
264
                return err
×
265
        }
×
UNCOV
266
        if err := mig.WriteChanConfig(&w, &c.RemoteChanCfg); err != nil {
×
267
                return err
×
268
        }
×
269

270
        // Make the tlv stream based on the legacy param.
UNCOV
271
        tlvStream, err := MakeTlvStream(c, legacy)
×
UNCOV
272
        if err != nil {
×
273
                return err
×
274
        }
×
275

UNCOV
276
        if err := tlvStream.Encode(&w); err != nil {
×
277
                return err
×
278
        }
×
279

UNCOV
280
        if err := chanBucket.Put(chanInfoKey, w.Bytes()); err != nil {
×
281
                return err
×
282
        }
×
283

284
        // Finally, add optional shutdown scripts for the local and remote peer
285
        // if they are present.
UNCOV
286
        if err := mig25.PutOptionalUpfrontShutdownScript(
×
UNCOV
287
                chanBucket, localUpfrontShutdownKey, c.LocalShutdownScript,
×
UNCOV
288
        ); err != nil {
×
289
                return err
×
290
        }
×
291

UNCOV
292
        return mig25.PutOptionalUpfrontShutdownScript(
×
UNCOV
293
                chanBucket, remoteUpfrontShutdownKey, c.RemoteShutdownScript,
×
UNCOV
294
        )
×
295
}
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