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

lightningnetwork / lnd / 17373151115

01 Sep 2025 09:13AM UTC coverage: 66.657% (-0.02%) from 66.678%
17373151115

Pull #10182

github

web-flow
Merge 48f9e78c3 into cd6971ea1
Pull Request #10182: Aux feature bits

45 of 108 new or added lines in 4 files covered. (41.67%)

83 existing lines in 16 files now uncovered.

136034 of 204080 relevant lines covered (66.66%)

21495.48 hits per line

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

79.44
/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
)
11

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

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

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

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

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

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

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

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

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

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

92
        // AuxFeatures is an optional field that stores auxiliary feature bits
93
        // for custom channel negotiation. This is used by aux channel
94
        // implementations to negotiate custom channel behavior during
95
        // channel reestablishment.
96
        AuxFeatures fn.Option[AuxFeatureBits]
97

98
        // ExtraData is the set of data that was appended to this message to
99
        // fill out the full maximum transport message size. These fields can
100
        // be used to specify optional data such as custom TLV fields.
101
        ExtraData ExtraOpaqueData
102
}
103

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

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

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

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

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

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

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

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

149
        recordProducers := make([]tlv.RecordProducer, 0, 3)
116✔
150
        a.LocalNonce.WhenSome(func(localNonce Musig2NonceTLV) {
177✔
151
                recordProducers = append(recordProducers, &localNonce)
61✔
152
        })
61✔
153
        a.DynHeight.WhenSome(func(h DynHeight) {
164✔
154
                recordProducers = append(recordProducers, &h)
48✔
155
        })
48✔
156
        a.AuxFeatures.WhenSome(func(features AuxFeatureBits) {
116✔
NEW
157
                record := tlv.MakePrimitiveRecord(AuxFeatureBitsTLV, &features)
×
NEW
158
                recordProducers = append(recordProducers, &record)
×
NEW
159
        })
×
160

161
        err := EncodeMessageExtraData(&a.ExtraData, recordProducers...)
116✔
162
        if err != nil {
116✔
163
                return err
×
164
        }
×
165

166
        return WriteBytes(w, a.ExtraData)
116✔
167
}
168

169
// Decode deserializes a serialized ChannelReestablish stored in the passed
170
// io.Reader observing the specified protocol version.
171
//
172
// This is part of the lnwire.Message interface.
173
func (a *ChannelReestablish) Decode(r io.Reader, pver uint32) error {
179✔
174
        err := ReadElements(r,
179✔
175
                &a.ChanID,
179✔
176
                &a.NextLocalCommitHeight,
179✔
177
                &a.RemoteCommitTailHeight,
179✔
178
        )
179✔
179
        if err != nil {
184✔
180
                return err
5✔
181
        }
5✔
182

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

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

204
        // If the field is present, then we'll copy it over and proceed.
205
        copy(a.LastRemoteCommitSecret[:], buf[:])
171✔
206

171✔
207
        // We'll conclude by parsing out the commitment point. We don't check
171✔
208
        // the error in this case, as it has included the commit secret, then
171✔
209
        // they MUST also include the commit point.
171✔
210
        if err = ReadElement(r, &a.LocalUnrevokedCommitPoint); err != nil {
176✔
211
                return err
5✔
212
        }
5✔
213

214
        var tlvRecords ExtraOpaqueData
166✔
215
        if err := ReadElements(r, &tlvRecords); err != nil {
166✔
216
                return err
×
217
        }
×
218

219
        var (
166✔
220
                dynHeight         DynHeight
166✔
221
                localNonce        = a.LocalNonce.Zero()
166✔
222
                auxFeatures       AuxFeatureBits
166✔
223
                auxFeaturesRecord = tlv.MakePrimitiveRecord(
166✔
224
                        AuxFeatureBitsTLV, &auxFeatures,
166✔
225
                )
166✔
226
        )
166✔
227
        typeMap, err := tlvRecords.ExtractRecords(
166✔
228
                &localNonce, &dynHeight, &auxFeaturesRecord,
166✔
229
        )
166✔
230
        if err != nil {
206✔
231
                return err
40✔
232
        }
40✔
233

234
        if val, ok := typeMap[a.LocalNonce.TlvType()]; ok && val == nil {
188✔
235
                a.LocalNonce = tlv.SomeRecordT(localNonce)
62✔
236
        }
62✔
237
        if val, ok := typeMap[CRDynHeight]; ok && val == nil {
175✔
238
                a.DynHeight = fn.Some(dynHeight)
49✔
239
        }
49✔
240
        if val, ok := typeMap[AuxFeatureBitsTLV]; ok && val == nil {
126✔
NEW
241
                a.AuxFeatures = fn.Some(auxFeatures)
×
NEW
242
        }
×
243

244
        if len(tlvRecords) != 0 {
215✔
245
                a.ExtraData = tlvRecords
89✔
246
        }
89✔
247

248
        return nil
126✔
249
}
250

251
// MsgType returns the integer uniquely identifying this message type on the
252
// wire.
253
//
254
// This is part of the lnwire.Message interface.
255
func (a *ChannelReestablish) MsgType() MessageType {
322✔
256
        return MsgChannelReestablish
322✔
257
}
322✔
258

259
// SerializedSize returns the serialized size of the message in bytes.
260
//
261
// This is part of the lnwire.SizeableMessage interface.
262
func (a *ChannelReestablish) SerializedSize() (uint32, error) {
×
263
        return MessageSerializedSize(a)
×
264
}
×
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