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

lightningnetwork / lnd / 13211764208

08 Feb 2025 03:08AM UTC coverage: 49.288% (-9.5%) from 58.815%
13211764208

Pull #9489

github

calvinrzachman
itest: verify switchrpc server enforces send then track

We prevent the rpc server from allowing onion dispatches for
attempt IDs which have already been tracked by rpc clients.

This helps protect the client from leaking a duplicate onion
attempt. NOTE: This is not the only method for solving this
issue! The issue could be addressed via careful client side
programming which accounts for the uncertainty and async
nature of dispatching onions to a remote process via RPC.
This would require some lnd ChannelRouter changes for how
we intend to use these RPCs though.
Pull Request #9489: multi: add BuildOnion, SendOnion, and TrackOnion RPCs

474 of 990 new or added lines in 11 files covered. (47.88%)

27321 existing lines in 435 files now uncovered.

101192 of 205306 relevant lines covered (49.29%)

1.54 hits per line

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

60.22
/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 {
3✔
23
        return tlv.MakePrimitiveRecord(CRDynHeight, (*uint64)(d))
3✔
24
}
3✔
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
        // ExtraData is the set of data that was appended to this message to
93
        // fill out the full maximum transport message size. These fields can
94
        // be used to specify optional data such as custom TLV fields.
95
        ExtraData ExtraOpaqueData
96
}
97

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

102
// Encode serializes the target ChannelReestablish into the passed io.Writer
103
// observing the protocol version specified.
104
//
105
// This is part of the lnwire.Message interface.
106
func (a *ChannelReestablish) Encode(w *bytes.Buffer, pver uint32) error {
3✔
107
        if err := WriteChannelID(w, a.ChanID); err != nil {
3✔
108
                return err
×
109
        }
×
110

111
        if err := WriteUint64(w, a.NextLocalCommitHeight); err != nil {
3✔
112
                return err
×
113
        }
×
114

115
        if err := WriteUint64(w, a.RemoteCommitTailHeight); err != nil {
3✔
116
                return err
×
117
        }
×
118

119
        // If the commit point wasn't sent, then we won't write out any of the
120
        // remaining fields as they're optional.
121
        if a.LocalUnrevokedCommitPoint == nil {
3✔
UNCOV
122
                // However, we'll still write out the extra data if it's
×
UNCOV
123
                // present.
×
UNCOV
124
                //
×
UNCOV
125
                // NOTE: This is here primarily for the quickcheck tests, in
×
UNCOV
126
                // practice, we'll always populate this field.
×
UNCOV
127
                return WriteBytes(w, a.ExtraData)
×
UNCOV
128
        }
×
129

130
        // Otherwise, we'll write out the remaining elements.
131
        if err := WriteBytes(w, a.LastRemoteCommitSecret[:]); err != nil {
3✔
132
                return err
×
133
        }
×
134

135
        if err := WritePublicKey(w, a.LocalUnrevokedCommitPoint); err != nil {
3✔
136
                return err
×
137
        }
×
138

139
        recordProducers := make([]tlv.RecordProducer, 0, 1)
3✔
140
        a.LocalNonce.WhenSome(func(localNonce Musig2NonceTLV) {
6✔
141
                recordProducers = append(recordProducers, &localNonce)
3✔
142
        })
3✔
143
        a.DynHeight.WhenSome(func(h DynHeight) {
3✔
UNCOV
144
                recordProducers = append(recordProducers, &h)
×
UNCOV
145
        })
×
146

147
        err := EncodeMessageExtraData(&a.ExtraData, recordProducers...)
3✔
148
        if err != nil {
3✔
149
                return err
×
150
        }
×
151

152
        return WriteBytes(w, a.ExtraData)
3✔
153
}
154

155
// Decode deserializes a serialized ChannelReestablish stored in the passed
156
// io.Reader observing the specified protocol version.
157
//
158
// This is part of the lnwire.Message interface.
159
func (a *ChannelReestablish) Decode(r io.Reader, pver uint32) error {
3✔
160
        err := ReadElements(r,
3✔
161
                &a.ChanID,
3✔
162
                &a.NextLocalCommitHeight,
3✔
163
                &a.RemoteCommitTailHeight,
3✔
164
        )
3✔
165
        if err != nil {
3✔
UNCOV
166
                return err
×
UNCOV
167
        }
×
168

169
        // This message has currently defined optional fields. As a result,
170
        // we'll only proceed if there's still bytes remaining within the
171
        // reader.
172
        //
173
        // We'll manually parse out the optional fields in order to be able to
174
        // still utilize the io.Reader interface.
175

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

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

3✔
193
        // We'll conclude by parsing out the commitment point. We don't check
3✔
194
        // the error in this case, as it has included the commit secret, then
3✔
195
        // they MUST also include the commit point.
3✔
196
        if err = ReadElement(r, &a.LocalUnrevokedCommitPoint); err != nil {
3✔
UNCOV
197
                return err
×
UNCOV
198
        }
×
199

200
        var tlvRecords ExtraOpaqueData
3✔
201
        if err := ReadElements(r, &tlvRecords); err != nil {
3✔
202
                return err
×
203
        }
×
204

205
        var (
3✔
206
                dynHeight  DynHeight
3✔
207
                localNonce = a.LocalNonce.Zero()
3✔
208
        )
3✔
209
        typeMap, err := tlvRecords.ExtractRecords(
3✔
210
                &localNonce, &dynHeight,
3✔
211
        )
3✔
212
        if err != nil {
3✔
UNCOV
213
                return err
×
UNCOV
214
        }
×
215

216
        if val, ok := typeMap[a.LocalNonce.TlvType()]; ok && val == nil {
6✔
217
                a.LocalNonce = tlv.SomeRecordT(localNonce)
3✔
218
        }
3✔
219
        if val, ok := typeMap[CRDynHeight]; ok && val == nil {
3✔
UNCOV
220
                a.DynHeight = fn.Some(dynHeight)
×
UNCOV
221
        }
×
222

223
        if len(tlvRecords) != 0 {
6✔
224
                a.ExtraData = tlvRecords
3✔
225
        }
3✔
226

227
        return nil
3✔
228
}
229

230
// MsgType returns the integer uniquely identifying this message type on the
231
// wire.
232
//
233
// This is part of the lnwire.Message interface.
234
func (a *ChannelReestablish) MsgType() MessageType {
3✔
235
        return MsgChannelReestablish
3✔
236
}
3✔
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