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

lightningnetwork / lnd / 13980275562

20 Mar 2025 10:06PM UTC coverage: 58.6% (-10.2%) from 68.789%
13980275562

Pull #9623

github

web-flow
Merge b9b960345 into 09b674508
Pull Request #9623: Size msg test msg

0 of 1518 new or added lines in 42 files covered. (0.0%)

26603 existing lines in 443 files now uncovered.

96807 of 165200 relevant lines covered (58.6%)

1.82 hits per line

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

45.53
/lnwire/channel_reestablish.go
1
package lnwire
2

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

7
        "github.com/btcsuite/btcd/btcec/v2"
8
        "github.com/lightningnetwork/lnd/fn/v2"
9
        "github.com/lightningnetwork/lnd/tlv"
10
        "pgregory.net/rapid"
11
)
12

13
const (
14
        CRDynHeight tlv.Type = 20
15
)
16

17
// DynHeight is a newtype wrapper to get the proper RecordProducer instance
18
// to smoothly integrate with the ChannelReestablish Message instance.
19
type DynHeight uint64
20

21
// Record implements the RecordProducer interface, allowing a full tlv.Record
22
// object to be constructed from a DynHeight.
23
func (d *DynHeight) Record() tlv.Record {
3✔
24
        return tlv.MakePrimitiveRecord(CRDynHeight, (*uint64)(d))
3✔
25
}
3✔
26

27
// ChannelReestablish is a message sent between peers that have an existing
28
// open channel upon connection reestablishment. This message allows both sides
29
// to report their local state, and their current knowledge of the state of the
30
// remote commitment chain. If a deviation is detected and can be recovered
31
// from, then the necessary messages will be retransmitted. If the level of
32
// desynchronization is irreconcilable, then the channel will be force closed.
33
type ChannelReestablish struct {
34
        // ChanID is the channel ID of the channel state we're attempting to
35
        // synchronize with the remote party.
36
        ChanID ChannelID
37

38
        // NextLocalCommitHeight is the next local commitment height of the
39
        // sending party. If the height of the sender's commitment chain from
40
        // the receiver's Pov is one less that this number, then the sender
41
        // should re-send the *exact* same proposed commitment.
42
        //
43
        // In other words, the receiver should re-send their last sent
44
        // commitment iff:
45
        //
46
        //  * NextLocalCommitHeight == remoteCommitChain.Height
47
        //
48
        // This covers the case of a lost commitment which was sent by the
49
        // sender of this message, but never received by the receiver of this
50
        // message.
51
        NextLocalCommitHeight uint64
52

53
        // RemoteCommitTailHeight is the height of the receiving party's
54
        // unrevoked commitment from the PoV of the sender of this message. If
55
        // the height of the receiver's commitment is *one more* than this
56
        // value, then their prior RevokeAndAck message should be
57
        // retransmitted.
58
        //
59
        // In other words, the receiver should re-send their last sent
60
        // RevokeAndAck message iff:
61
        //
62
        //  * localCommitChain.tail().Height == RemoteCommitTailHeight + 1
63
        //
64
        // This covers the case of a lost revocation, wherein the receiver of
65
        // the message sent a revocation for a prior state, but the sender of
66
        // the message never fully processed it.
67
        RemoteCommitTailHeight uint64
68

69
        // LastRemoteCommitSecret is the last commitment secret that the
70
        // receiving node has sent to the sending party. This will be the
71
        // secret of the last revoked commitment transaction. Including this
72
        // provides proof that the sending node at least knows of this state,
73
        // as they couldn't have produced it if it wasn't sent, as the value
74
        // can be authenticated by querying the shachain or the receiving
75
        // party.
76
        LastRemoteCommitSecret [32]byte
77

78
        // LocalUnrevokedCommitPoint is the commitment point used in the
79
        // current un-revoked commitment transaction of the sending party.
80
        LocalUnrevokedCommitPoint *btcec.PublicKey
81

82
        // LocalNonce is an optional field that stores a local musig2 nonce.
83
        // This will only be populated if the simple taproot channels type was
84
        // negotiated.
85
        //
86
        LocalNonce OptMusig2NonceTLV
87

88
        // DynHeight is an optional field that stores the dynamic commitment
89
        // negotiation height that is incremented upon successful completion of
90
        // a dynamic commitment negotiation
91
        DynHeight fn.Option[DynHeight]
92

93
        // ExtraData is the set of data that was appended to this message to
94
        // fill out the full maximum transport message size. These fields can
95
        // be used to specify optional data such as custom TLV fields.
96
        ExtraData ExtraOpaqueData
97
}
98

99
// A compile time check to ensure ChannelReestablish implements the
100
// lnwire.Message interface.
101
var _ Message = (*ChannelReestablish)(nil)
102

103
// A compile time check to ensure ChannelReestablish implements the
104
// lnwire.SizeableMessage interface.
105
var _ SizeableMessage = (*ChannelReestablish)(nil)
106

107
// A compile time check to ensure ChannelReestablish implements the
108
// lnwire.TestMessage interface.
109
var _ TestMessage = (*ChannelReestablish)(nil)
110

111
// Encode serializes the target ChannelReestablish into the passed io.Writer
112
// observing the protocol version specified.
113
//
114
// This is part of the lnwire.Message interface.
115
func (a *ChannelReestablish) Encode(w *bytes.Buffer, pver uint32) error {
3✔
116
        if err := WriteChannelID(w, a.ChanID); err != nil {
3✔
117
                return err
×
118
        }
×
119

120
        if err := WriteUint64(w, a.NextLocalCommitHeight); err != nil {
3✔
121
                return err
×
122
        }
×
123

124
        if err := WriteUint64(w, a.RemoteCommitTailHeight); err != nil {
3✔
125
                return err
×
126
        }
×
127

128
        // If the commit point wasn't sent, then we won't write out any of the
129
        // remaining fields as they're optional.
130
        if a.LocalUnrevokedCommitPoint == nil {
3✔
UNCOV
131
                // However, we'll still write out the extra data if it's
×
UNCOV
132
                // present.
×
UNCOV
133
                //
×
UNCOV
134
                // NOTE: This is here primarily for the quickcheck tests, in
×
UNCOV
135
                // practice, we'll always populate this field.
×
UNCOV
136
                return WriteBytes(w, a.ExtraData)
×
UNCOV
137
        }
×
138

139
        // Otherwise, we'll write out the remaining elements.
140
        if err := WriteBytes(w, a.LastRemoteCommitSecret[:]); err != nil {
3✔
141
                return err
×
142
        }
×
143

144
        if err := WritePublicKey(w, a.LocalUnrevokedCommitPoint); err != nil {
3✔
145
                return err
×
146
        }
×
147

148
        recordProducers := make([]tlv.RecordProducer, 0, 1)
3✔
149
        a.LocalNonce.WhenSome(func(localNonce Musig2NonceTLV) {
6✔
150
                recordProducers = append(recordProducers, &localNonce)
3✔
151
        })
3✔
152
        a.DynHeight.WhenSome(func(h DynHeight) {
3✔
UNCOV
153
                recordProducers = append(recordProducers, &h)
×
UNCOV
154
        })
×
155

156
        err := EncodeMessageExtraData(&a.ExtraData, recordProducers...)
3✔
157
        if err != nil {
3✔
158
                return err
×
159
        }
×
160

161
        return WriteBytes(w, a.ExtraData)
3✔
162
}
163

164
// Decode deserializes a serialized ChannelReestablish stored in the passed
165
// io.Reader observing the specified protocol version.
166
//
167
// This is part of the lnwire.Message interface.
168
func (a *ChannelReestablish) Decode(r io.Reader, pver uint32) error {
3✔
169
        err := ReadElements(r,
3✔
170
                &a.ChanID,
3✔
171
                &a.NextLocalCommitHeight,
3✔
172
                &a.RemoteCommitTailHeight,
3✔
173
        )
3✔
174
        if err != nil {
3✔
UNCOV
175
                return err
×
UNCOV
176
        }
×
177

178
        // This message has currently defined optional fields. As a result,
179
        // we'll only proceed if there's still bytes remaining within the
180
        // reader.
181
        //
182
        // We'll manually parse out the optional fields in order to be able to
183
        // still utilize the io.Reader interface.
184

185
        // We'll first attempt to read the optional commit secret, if we're at
186
        // the EOF, then this means the field wasn't included so we can exit
187
        // early.
188
        var buf [32]byte
3✔
189
        _, err = io.ReadFull(r, buf[:32])
3✔
190
        if err == io.EOF {
3✔
UNCOV
191
                // If there aren't any more bytes, then we'll emplace an empty
×
UNCOV
192
                // extra data to make our quickcheck tests happy.
×
UNCOV
193
                a.ExtraData = make([]byte, 0)
×
UNCOV
194
                return nil
×
195
        } else if err != nil {
3✔
UNCOV
196
                return err
×
UNCOV
197
        }
×
198

199
        // If the field is present, then we'll copy it over and proceed.
200
        copy(a.LastRemoteCommitSecret[:], buf[:])
3✔
201

3✔
202
        // We'll conclude by parsing out the commitment point. We don't check
3✔
203
        // the error in this case, as it has included the commit secret, then
3✔
204
        // they MUST also include the commit point.
3✔
205
        if err = ReadElement(r, &a.LocalUnrevokedCommitPoint); err != nil {
3✔
UNCOV
206
                return err
×
UNCOV
207
        }
×
208

209
        var tlvRecords ExtraOpaqueData
3✔
210
        if err := ReadElements(r, &tlvRecords); err != nil {
3✔
211
                return err
×
212
        }
×
213

214
        var (
3✔
215
                dynHeight  DynHeight
3✔
216
                localNonce = a.LocalNonce.Zero()
3✔
217
        )
3✔
218
        typeMap, err := tlvRecords.ExtractRecords(
3✔
219
                &localNonce, &dynHeight,
3✔
220
        )
3✔
221
        if err != nil {
3✔
UNCOV
222
                return err
×
UNCOV
223
        }
×
224

225
        if val, ok := typeMap[a.LocalNonce.TlvType()]; ok && val == nil {
6✔
226
                a.LocalNonce = tlv.SomeRecordT(localNonce)
3✔
227
        }
3✔
228
        if val, ok := typeMap[CRDynHeight]; ok && val == nil {
3✔
UNCOV
229
                a.DynHeight = fn.Some(dynHeight)
×
UNCOV
230
        }
×
231

232
        if len(tlvRecords) != 0 {
6✔
233
                a.ExtraData = tlvRecords
3✔
234
        }
3✔
235

236
        return nil
3✔
237
}
238

239
// MsgType returns the integer uniquely identifying this message type on the
240
// wire.
241
//
242
// This is part of the lnwire.Message interface.
243
func (a *ChannelReestablish) MsgType() MessageType {
3✔
244
        return MsgChannelReestablish
3✔
245
}
3✔
246

247
// SerializedSize returns the serialized size of the message in bytes.
248
//
249
// This is part of the lnwire.SizeableMessage interface.
NEW
250
func (a *ChannelReestablish) SerializedSize() (uint32, error) {
×
NEW
251
        return MessageSerializedSize(a)
×
NEW
252
}
×
253

254
// RandTestMessage populates the message with random data suitable for testing.
255
// It uses the rapid testing framework to generate random values.
256
//
257
// This is part of the TestMessage interface.
NEW
258
func (a *ChannelReestablish) RandTestMessage(t *rapid.T) Message {
×
NEW
259
        msg := &ChannelReestablish{
×
NEW
260
                ChanID: RandChannelID(t),
×
NEW
261
                NextLocalCommitHeight: rapid.Uint64().Draw(
×
NEW
262
                        t, "nextLocalCommitHeight",
×
NEW
263
                ),
×
NEW
264
                RemoteCommitTailHeight: rapid.Uint64().Draw(
×
NEW
265
                        t, "remoteCommitTailHeight",
×
NEW
266
                ),
×
NEW
267
                LastRemoteCommitSecret:    RandPaymentPreimage(t),
×
NEW
268
                LocalUnrevokedCommitPoint: RandPubKey(t),
×
NEW
269
                ExtraData:                 RandExtraOpaqueData(t, nil),
×
NEW
270
        }
×
NEW
271

×
NEW
272
        // Randomly decide whether to include optional fields
×
NEW
273
        includeLocalNonce := rapid.Bool().Draw(t, "includeLocalNonce")
×
NEW
274
        includeDynHeight := rapid.Bool().Draw(t, "includeDynHeight")
×
NEW
275

×
NEW
276
        if includeLocalNonce {
×
NEW
277
                nonce := RandMusig2Nonce(t)
×
NEW
278
                msg.LocalNonce = SomeMusig2Nonce(nonce)
×
NEW
279
        }
×
280

NEW
281
        if includeDynHeight {
×
NEW
282
                height := DynHeight(rapid.Uint64().Draw(t, "dynHeight"))
×
NEW
283
                msg.DynHeight = fn.Some(height)
×
NEW
284
        }
×
285

NEW
286
        return msg
×
287
}
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