• 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

67.22
/lnwire/writer.go
1
package lnwire
2

3
import (
4
        "bytes"
5
        "encoding/binary"
6
        "errors"
7
        "fmt"
8
        "image/color"
9
        "math"
10
        "net"
11

12
        "github.com/btcsuite/btcd/btcec/v2"
13
        "github.com/btcsuite/btcd/btcutil"
14
        "github.com/btcsuite/btcd/wire"
15
        "github.com/lightningnetwork/lnd/tor"
16
)
17

18
var (
19
        // ErrNilFeatureVector is returned when the supplied feature is nil.
20
        ErrNilFeatureVector = errors.New("cannot write nil feature vector")
21

22
        // ErrPkScriptTooLong is returned when the length of the provided
23
        // script exceeds 34.
24
        ErrPkScriptTooLong = errors.New("'PkScript' too long")
25

26
        // ErrNilTCPAddress is returned when the supplied address is nil.
27
        ErrNilTCPAddress = errors.New("cannot write nil TCPAddr")
28

29
        // ErrNilOnionAddress is returned when the supplied address is nil.
30
        ErrNilOnionAddress = errors.New("cannot write nil onion address")
31

32
        // ErrNilNetAddress is returned when a nil value is used in []net.Addr.
33
        ErrNilNetAddress = errors.New("cannot write nil address")
34

35
        // ErrNilOpaqueAddrs is returned when the supplied address is nil.
36
        ErrNilOpaqueAddrs = errors.New("cannot write nil OpaqueAddrs")
37

38
        // ErrNilPublicKey is returned when a nil pubkey is used.
39
        ErrNilPublicKey = errors.New("cannot write nil pubkey")
40

41
        // ErrUnknownServiceLength is returned when the onion service length is
42
        // unknown.
43
        ErrUnknownServiceLength = errors.New("unknown onion service length")
44
)
45

46
// ErrOutpointIndexTooBig is used when the outpoint index exceeds the max value
47
// of uint16.
UNCOV
48
func ErrOutpointIndexTooBig(index uint32) error {
×
UNCOV
49
        return fmt.Errorf(
×
UNCOV
50
                "index for outpoint (%v) is greater than "+
×
UNCOV
51
                        "max index of %v", index, math.MaxUint16,
×
UNCOV
52
        )
×
UNCOV
53
}
×
54

55
// WriteBytes appends the given bytes to the provided buffer.
56
func WriteBytes(buf *bytes.Buffer, b []byte) error {
3✔
57
        _, err := buf.Write(b)
3✔
58
        return err
3✔
59
}
3✔
60

61
// WriteUint8 appends the uint8 to the provided buffer.
62
func WriteUint8(buf *bytes.Buffer, n uint8) error {
3✔
63
        _, err := buf.Write([]byte{n})
3✔
64
        return err
3✔
65
}
3✔
66

67
// WriteUint16 appends the uint16 to the provided buffer. It encodes the
68
// integer using big endian byte order.
69
func WriteUint16(buf *bytes.Buffer, n uint16) error {
3✔
70
        var b [2]byte
3✔
71
        binary.BigEndian.PutUint16(b[:], n)
3✔
72
        _, err := buf.Write(b[:])
3✔
73
        return err
3✔
74
}
3✔
75

76
// WriteUint32 appends the uint32 to the provided buffer. It encodes the
77
// integer using big endian byte order.
78
func WriteUint32(buf *bytes.Buffer, n uint32) error {
3✔
79
        var b [4]byte
3✔
80
        binary.BigEndian.PutUint32(b[:], n)
3✔
81
        _, err := buf.Write(b[:])
3✔
82
        return err
3✔
83
}
3✔
84

85
// WriteUint64 appends the uint64 to the provided buffer. It encodes the
86
// integer using big endian byte order.
87
func WriteUint64(buf *bytes.Buffer, n uint64) error {
3✔
88
        var b [8]byte
3✔
89
        binary.BigEndian.PutUint64(b[:], n)
3✔
90
        _, err := buf.Write(b[:])
3✔
91
        return err
3✔
92
}
3✔
93

94
// WriteSatoshi appends the Satoshi value to the provided buffer.
95
func WriteSatoshi(buf *bytes.Buffer, amount btcutil.Amount) error {
3✔
96
        return WriteUint64(buf, uint64(amount))
3✔
97
}
3✔
98

99
// WriteMilliSatoshi appends the MilliSatoshi value to the provided buffer.
100
func WriteMilliSatoshi(buf *bytes.Buffer, amount MilliSatoshi) error {
3✔
101
        return WriteUint64(buf, uint64(amount))
3✔
102
}
3✔
103

104
// WritePublicKey appends the compressed public key to the provided buffer.
105
func WritePublicKey(buf *bytes.Buffer, pub *btcec.PublicKey) error {
3✔
106
        if pub == nil {
3✔
UNCOV
107
                return ErrNilPublicKey
×
UNCOV
108
        }
×
109

110
        serializedPubkey := pub.SerializeCompressed()
3✔
111
        return WriteBytes(buf, serializedPubkey)
3✔
112
}
113

114
// WriteChannelID appends the ChannelID to the provided buffer.
115
func WriteChannelID(buf *bytes.Buffer, channelID ChannelID) error {
3✔
116
        return WriteBytes(buf, channelID[:])
3✔
117
}
3✔
118

119
// WriteNodeAlias appends the alias to the provided buffer.
120
func WriteNodeAlias(buf *bytes.Buffer, alias NodeAlias) error {
3✔
121
        return WriteBytes(buf, alias[:])
3✔
122
}
3✔
123

124
// WriteShortChannelID appends the ShortChannelID to the provided buffer. It
125
// encodes the BlockHeight and TxIndex each using 3 bytes with big endian byte
126
// order, and encodes txPosition using 2 bytes with big endian byte order.
127
func WriteShortChannelID(buf *bytes.Buffer, shortChanID ShortChannelID) error {
3✔
128
        // Check that field fit in 3 bytes and write the blockHeight
3✔
129
        if shortChanID.BlockHeight > ((1 << 24) - 1) {
3✔
130
                return errors.New("block height should fit in 3 bytes")
×
131
        }
×
132

133
        var blockHeight [4]byte
3✔
134
        binary.BigEndian.PutUint32(blockHeight[:], shortChanID.BlockHeight)
3✔
135

3✔
136
        if _, err := buf.Write(blockHeight[1:]); err != nil {
3✔
137
                return err
×
138
        }
×
139

140
        // Check that field fit in 3 bytes and write the txIndex
141
        if shortChanID.TxIndex > ((1 << 24) - 1) {
3✔
142
                return errors.New("tx index should fit in 3 bytes")
×
143
        }
×
144

145
        var txIndex [4]byte
3✔
146
        binary.BigEndian.PutUint32(txIndex[:], shortChanID.TxIndex)
3✔
147
        if _, err := buf.Write(txIndex[1:]); err != nil {
3✔
148
                return err
×
149
        }
×
150

151
        // Write the TxPosition
152
        return WriteUint16(buf, shortChanID.TxPosition)
3✔
153
}
154

155
// WriteSig appends the signature to the provided buffer.
156
func WriteSig(buf *bytes.Buffer, sig Sig) error {
3✔
157
        return WriteBytes(buf, sig.bytes[:])
3✔
158
}
3✔
159

160
// WriteSigs appends the slice of signatures to the provided buffer with its
161
// length.
162
func WriteSigs(buf *bytes.Buffer, sigs []Sig) error {
3✔
163
        // Write the length of the sigs.
3✔
164
        if err := WriteUint16(buf, uint16(len(sigs))); err != nil {
3✔
165
                return err
×
166
        }
×
167

168
        for _, sig := range sigs {
6✔
169
                if err := WriteSig(buf, sig); err != nil {
3✔
170
                        return err
×
171
                }
×
172
        }
173
        return nil
3✔
174
}
175

176
// WriteFailCode appends the FailCode to the provided buffer.
177
func WriteFailCode(buf *bytes.Buffer, e FailCode) error {
3✔
178
        return WriteUint16(buf, uint16(e))
3✔
179
}
3✔
180

181
// WriteRawFeatureVector encodes the feature using the feature's Encode method
182
// and appends the data to the provided buffer. An error will return if the
183
// passed feature is nil.
184
func WriteRawFeatureVector(buf *bytes.Buffer, feature *RawFeatureVector) error {
3✔
185
        if feature == nil {
3✔
UNCOV
186
                return ErrNilFeatureVector
×
UNCOV
187
        }
×
188

189
        return feature.Encode(buf)
3✔
190
}
191

192
// WriteColorRGBA appends the RGBA color using three bytes.
193
func WriteColorRGBA(buf *bytes.Buffer, e color.RGBA) error {
3✔
194
        // Write R
3✔
195
        if err := WriteUint8(buf, e.R); err != nil {
3✔
196
                return err
×
197
        }
×
198

199
        // Write G
200
        if err := WriteUint8(buf, e.G); err != nil {
3✔
201
                return err
×
202
        }
×
203

204
        // Write B
205
        return WriteUint8(buf, e.B)
3✔
206
}
207

208
// WriteQueryEncoding appends the QueryEncoding to the provided buffer.
209
func WriteQueryEncoding(buf *bytes.Buffer, e QueryEncoding) error {
3✔
210
        return WriteUint8(buf, uint8(e))
3✔
211
}
3✔
212

213
// WriteFundingFlag appends the FundingFlag to the provided buffer.
214
func WriteFundingFlag(buf *bytes.Buffer, flag FundingFlag) error {
3✔
215
        return WriteUint8(buf, uint8(flag))
3✔
216
}
3✔
217

218
// WriteChanUpdateMsgFlags appends the update flag to the provided buffer.
219
func WriteChanUpdateMsgFlags(buf *bytes.Buffer, f ChanUpdateMsgFlags) error {
3✔
220
        return WriteUint8(buf, uint8(f))
3✔
221
}
3✔
222

223
// WriteChanUpdateChanFlags appends the update flag to the provided buffer.
224
func WriteChanUpdateChanFlags(buf *bytes.Buffer, f ChanUpdateChanFlags) error {
3✔
225
        return WriteUint8(buf, uint8(f))
3✔
226
}
3✔
227

228
// WriteDeliveryAddress appends the address to the provided buffer.
229
func WriteDeliveryAddress(buf *bytes.Buffer, addr DeliveryAddress) error {
3✔
230
        return writeDataWithLength(buf, addr)
3✔
231
}
3✔
232

233
// WritePingPayload appends the payload to the provided buffer.
UNCOV
234
func WritePingPayload(buf *bytes.Buffer, payload PingPayload) error {
×
UNCOV
235
        return writeDataWithLength(buf, payload)
×
UNCOV
236
}
×
237

238
// WritePongPayload appends the payload to the provided buffer.
UNCOV
239
func WritePongPayload(buf *bytes.Buffer, payload PongPayload) error {
×
UNCOV
240
        return writeDataWithLength(buf, payload)
×
UNCOV
241
}
×
242

243
// WriteWarningData appends the data to the provided buffer.
UNCOV
244
func WriteWarningData(buf *bytes.Buffer, data WarningData) error {
×
UNCOV
245
        return writeDataWithLength(buf, data)
×
UNCOV
246
}
×
247

248
// WriteErrorData appends the data to the provided buffer.
249
func WriteErrorData(buf *bytes.Buffer, data ErrorData) error {
3✔
250
        return writeDataWithLength(buf, data)
3✔
251
}
3✔
252

253
// WriteOpaqueReason appends the reason to the provided buffer.
254
func WriteOpaqueReason(buf *bytes.Buffer, reason OpaqueReason) error {
3✔
255
        return writeDataWithLength(buf, reason)
3✔
256
}
3✔
257

258
// WriteBool appends the boolean to the provided buffer.
259
func WriteBool(buf *bytes.Buffer, b bool) error {
3✔
260
        if b {
6✔
261
                return WriteBytes(buf, []byte{1})
3✔
262
        }
3✔
263
        return WriteBytes(buf, []byte{0})
3✔
264
}
265

266
// WritePkScript appends the script to the provided buffer. Returns an error if
267
// the provided script exceeds 34 bytes.
UNCOV
268
func WritePkScript(buf *bytes.Buffer, s PkScript) error {
×
UNCOV
269
        // The largest script we'll accept is a p2wsh which is exactly
×
UNCOV
270
        // 34 bytes long.
×
UNCOV
271
        scriptLength := len(s)
×
UNCOV
272
        if scriptLength > 34 {
×
UNCOV
273
                return ErrPkScriptTooLong
×
UNCOV
274
        }
×
275

UNCOV
276
        return wire.WriteVarBytes(buf, 0, s)
×
277
}
278

279
// WriteOutPoint appends the outpoint to the provided buffer.
280
func WriteOutPoint(buf *bytes.Buffer, p wire.OutPoint) error {
3✔
281
        // Before we write anything to the buffer, check the Index is sane.
3✔
282
        if p.Index > math.MaxUint16 {
3✔
UNCOV
283
                return ErrOutpointIndexTooBig(p.Index)
×
UNCOV
284
        }
×
285

286
        var h [32]byte
3✔
287
        copy(h[:], p.Hash[:])
3✔
288
        if _, err := buf.Write(h[:]); err != nil {
3✔
289
                return err
×
290
        }
×
291

292
        // Write the index using two bytes.
293
        return WriteUint16(buf, uint16(p.Index))
3✔
294
}
295

296
// WriteTCPAddr appends the TCP address to the provided buffer, either a IPv4
297
// or a IPv6.
298
func WriteTCPAddr(buf *bytes.Buffer, addr *net.TCPAddr) error {
3✔
299
        if addr == nil {
3✔
UNCOV
300
                return ErrNilTCPAddress
×
UNCOV
301
        }
×
302

303
        // Make a slice of bytes to hold the data of descriptor and ip. At
304
        // most, we need 17 bytes - 1 byte for the descriptor, 16 bytes for
305
        // IPv6.
306
        data := make([]byte, 0, 17)
3✔
307

3✔
308
        if addr.IP.To4() != nil {
6✔
309
                data = append(data, uint8(tcp4Addr))
3✔
310
                data = append(data, addr.IP.To4()...)
3✔
311
        } else {
6✔
312
                data = append(data, uint8(tcp6Addr))
3✔
313
                data = append(data, addr.IP.To16()...)
3✔
314
        }
3✔
315

316
        if _, err := buf.Write(data); err != nil {
3✔
317
                return err
×
318
        }
×
319

320
        return WriteUint16(buf, uint16(addr.Port))
3✔
321
}
322

323
// WriteOnionAddr appends the onion address to the provided buffer.
324
func WriteOnionAddr(buf *bytes.Buffer, addr *tor.OnionAddr) error {
3✔
325
        if addr == nil {
3✔
UNCOV
326
                return ErrNilOnionAddress
×
UNCOV
327
        }
×
328

329
        var (
3✔
330
                suffixIndex int
3✔
331
                descriptor  []byte
3✔
332
        )
3✔
333

3✔
334
        // Decide the suffixIndex and descriptor.
3✔
335
        switch len(addr.OnionService) {
3✔
336
        case tor.V2Len:
3✔
337
                descriptor = []byte{byte(v2OnionAddr)}
3✔
338
                suffixIndex = tor.V2Len - tor.OnionSuffixLen
3✔
339

340
        case tor.V3Len:
3✔
341
                descriptor = []byte{byte(v3OnionAddr)}
3✔
342
                suffixIndex = tor.V3Len - tor.OnionSuffixLen
3✔
343

UNCOV
344
        default:
×
UNCOV
345
                return ErrUnknownServiceLength
×
346
        }
347

348
        // Decode the address.
349
        host, err := tor.Base32Encoding.DecodeString(
3✔
350
                addr.OnionService[:suffixIndex],
3✔
351
        )
3✔
352
        if err != nil {
3✔
UNCOV
353
                return err
×
UNCOV
354
        }
×
355

356
        // Perform the actual write when the above checks passed.
357
        if _, err := buf.Write(descriptor); err != nil {
3✔
358
                return err
×
359
        }
×
360
        if _, err := buf.Write(host); err != nil {
3✔
361
                return err
×
362
        }
×
363

364
        return WriteUint16(buf, uint16(addr.Port))
3✔
365
}
366

367
// WriteOpaqueAddrs appends the payload of the given OpaqueAddrs to buffer.
UNCOV
368
func WriteOpaqueAddrs(buf *bytes.Buffer, addr *OpaqueAddrs) error {
×
UNCOV
369
        if addr == nil {
×
370
                return ErrNilOpaqueAddrs
×
371
        }
×
372

UNCOV
373
        _, err := buf.Write(addr.Payload)
×
UNCOV
374
        return err
×
375
}
376

377
// WriteNetAddrs appends a slice of addresses to the provided buffer with the
378
// length info.
379
func WriteNetAddrs(buf *bytes.Buffer, addresses []net.Addr) error {
3✔
380
        // First, we'll encode all the addresses into an intermediate
3✔
381
        // buffer. We need to do this in order to compute the total
3✔
382
        // length of the addresses.
3✔
383
        buffer := make([]byte, 0, MaxMsgBody)
3✔
384
        addrBuf := bytes.NewBuffer(buffer)
3✔
385

3✔
386
        for _, address := range addresses {
6✔
387
                switch a := address.(type) {
3✔
388
                case *net.TCPAddr:
3✔
389
                        if err := WriteTCPAddr(addrBuf, a); err != nil {
3✔
390
                                return err
×
391
                        }
×
392
                case *tor.OnionAddr:
3✔
393
                        if err := WriteOnionAddr(addrBuf, a); err != nil {
3✔
394
                                return err
×
395
                        }
×
UNCOV
396
                case *OpaqueAddrs:
×
UNCOV
397
                        if err := WriteOpaqueAddrs(addrBuf, a); err != nil {
×
398
                                return err
×
399
                        }
×
UNCOV
400
                default:
×
UNCOV
401
                        return ErrNilNetAddress
×
402
                }
403
        }
404

405
        // With the addresses fully encoded, we can now write out data.
406
        return writeDataWithLength(buf, addrBuf.Bytes())
3✔
407
}
408

409
// writeDataWithLength writes the data and its length to the buffer.
410
func writeDataWithLength(buf *bytes.Buffer, data []byte) error {
3✔
411
        var l [2]byte
3✔
412
        binary.BigEndian.PutUint16(l[:], uint16(len(data)))
3✔
413
        if _, err := buf.Write(l[:]); err != nil {
3✔
414
                return err
×
415
        }
×
416

417
        _, err := buf.Write(data)
3✔
418
        return err
3✔
419
}
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