• 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

0.0
/watchtower/wtdb/migration8/codec.go
1
package migration8
2

3
import (
4
        "bytes"
5
        "encoding/binary"
6
        "encoding/hex"
7
        "fmt"
8
        "io"
9

10
        "github.com/btcsuite/btcd/wire"
11
        "github.com/lightningnetwork/lnd/tlv"
12
)
13

14
// BreachHintSize is the length of the identifier used to detect remote
15
// commitment broadcasts.
16
const BreachHintSize = 16
17

18
// BreachHint is the first 16-bytes of SHA256(txid), which is used to identify
19
// the breach transaction.
20
type BreachHint [BreachHintSize]byte
21

22
// ChannelID is a series of 32-bytes that uniquely identifies all channels
23
// within the network. The ChannelID is computed using the outpoint of the
24
// funding transaction (the txid, and output index). Given a funding output the
25
// ChannelID can be calculated by XOR'ing the big-endian serialization of the
26
// txid and the big-endian serialization of the output index, truncated to
27
// 2 bytes.
28
type ChannelID [32]byte
29

30
// writeBigSize will encode the given uint64 as a BigSize byte slice.
UNCOV
31
func writeBigSize(i uint64) ([]byte, error) {
×
UNCOV
32
        var b bytes.Buffer
×
UNCOV
33
        err := tlv.WriteVarInt(&b, i, &[8]byte{})
×
UNCOV
34
        if err != nil {
×
35
                return nil, err
×
36
        }
×
37

UNCOV
38
        return b.Bytes(), nil
×
39
}
40

41
// readBigSize converts the given byte slice into a uint64 and assumes that the
42
// bytes slice is using BigSize encoding.
UNCOV
43
func readBigSize(b []byte) (uint64, error) {
×
UNCOV
44
        r := bytes.NewReader(b)
×
UNCOV
45
        i, err := tlv.ReadVarInt(r, &[8]byte{})
×
UNCOV
46
        if err != nil {
×
47
                return 0, err
×
48
        }
×
49

UNCOV
50
        return i, nil
×
51
}
52

53
// CommittedUpdate holds a state update sent by a client along with its
54
// allocated sequence number and the exact remote commitment the encrypted
55
// justice transaction can rectify.
56
type CommittedUpdate struct {
57
        // SeqNum is the unique sequence number allocated by the session to this
58
        // update.
59
        SeqNum uint16
60

61
        CommittedUpdateBody
62
}
63

64
// BackupID identifies a particular revoked, remote commitment by channel id and
65
// commitment height.
66
type BackupID struct {
67
        // ChanID is the channel id of the revoked commitment.
68
        ChanID ChannelID
69

70
        // CommitHeight is the commitment height of the revoked commitment.
71
        CommitHeight uint64
72
}
73

74
// Encode writes the BackupID from the passed io.Writer.
UNCOV
75
func (b *BackupID) Encode(w io.Writer) error {
×
UNCOV
76
        return WriteElements(w,
×
UNCOV
77
                b.ChanID,
×
UNCOV
78
                b.CommitHeight,
×
UNCOV
79
        )
×
UNCOV
80
}
×
81

82
// Decode reads a BackupID from the passed io.Reader.
UNCOV
83
func (b *BackupID) Decode(r io.Reader) error {
×
UNCOV
84
        return ReadElements(r,
×
UNCOV
85
                &b.ChanID,
×
UNCOV
86
                &b.CommitHeight,
×
UNCOV
87
        )
×
UNCOV
88
}
×
89

90
// String returns a human-readable encoding of a BackupID.
91
func (b BackupID) String() string {
×
92
        return fmt.Sprintf("backup(%v, %d)", b.ChanID, b.CommitHeight)
×
93
}
×
94

95
// WriteElements serializes a variadic list of elements into the given
96
// io.Writer.
UNCOV
97
func WriteElements(w io.Writer, elements ...interface{}) error {
×
UNCOV
98
        for _, element := range elements {
×
UNCOV
99
                if err := WriteElement(w, element); err != nil {
×
100
                        return err
×
101
                }
×
102
        }
103

UNCOV
104
        return nil
×
105
}
106

107
// ReadElements deserializes the provided io.Reader into a variadic list of
108
// target elements.
UNCOV
109
func ReadElements(r io.Reader, elements ...interface{}) error {
×
UNCOV
110
        for _, element := range elements {
×
UNCOV
111
                if err := ReadElement(r, element); err != nil {
×
112
                        return err
×
113
                }
×
114
        }
115

UNCOV
116
        return nil
×
117
}
118

119
// WriteElement serializes a single element into the provided io.Writer.
UNCOV
120
func WriteElement(w io.Writer, element interface{}) error {
×
UNCOV
121
        switch e := element.(type) {
×
UNCOV
122
        case ChannelID:
×
UNCOV
123
                if _, err := w.Write(e[:]); err != nil {
×
124
                        return err
×
125
                }
×
126

UNCOV
127
        case uint64:
×
UNCOV
128
                if err := binary.Write(w, byteOrder, e); err != nil {
×
129
                        return err
×
130
                }
×
131

UNCOV
132
        case BreachHint:
×
UNCOV
133
                if _, err := w.Write(e[:]); err != nil {
×
134
                        return err
×
135
                }
×
136

UNCOV
137
        case []byte:
×
UNCOV
138
                if err := wire.WriteVarBytes(w, 0, e); err != nil {
×
139
                        return err
×
140
                }
×
141

142
        default:
×
143
                return fmt.Errorf("unexpected type")
×
144
        }
145

UNCOV
146
        return nil
×
147
}
148

149
// ReadElement deserializes a single element from the provided io.Reader.
UNCOV
150
func ReadElement(r io.Reader, element interface{}) error {
×
UNCOV
151
        switch e := element.(type) {
×
UNCOV
152
        case *ChannelID:
×
UNCOV
153
                if _, err := io.ReadFull(r, e[:]); err != nil {
×
154
                        return err
×
155
                }
×
156

UNCOV
157
        case *uint64:
×
UNCOV
158
                if err := binary.Read(r, byteOrder, e); err != nil {
×
159
                        return err
×
160
                }
×
161

UNCOV
162
        case *BreachHint:
×
UNCOV
163
                if _, err := io.ReadFull(r, e[:]); err != nil {
×
164
                        return err
×
165
                }
×
166

UNCOV
167
        case *[]byte:
×
UNCOV
168
                bytes, err := wire.ReadVarBytes(r, 0, 66000, "[]byte")
×
UNCOV
169
                if err != nil {
×
170
                        return err
×
171
                }
×
172

UNCOV
173
                *e = bytes
×
174

175
        default:
×
176
                return fmt.Errorf("unexpected type")
×
177
        }
178

UNCOV
179
        return nil
×
180
}
181

182
// CommittedUpdateBody represents the primary components of a CommittedUpdate.
183
// On disk, this is stored under the sequence number, which acts as its key.
184
type CommittedUpdateBody struct {
185
        // BackupID identifies the breached commitment that the encrypted blob
186
        // can spend from.
187
        BackupID BackupID
188

189
        // Hint is the 16-byte prefix of the revoked commitment transaction ID.
190
        Hint BreachHint
191

192
        // EncryptedBlob is a ciphertext containing the sweep information for
193
        // exacting justice if the commitment transaction matching the breach
194
        // hint is broadcast.
195
        EncryptedBlob []byte
196
}
197

198
// Encode writes the CommittedUpdateBody to the passed io.Writer.
UNCOV
199
func (u *CommittedUpdateBody) Encode(w io.Writer) error {
×
UNCOV
200
        err := u.BackupID.Encode(w)
×
UNCOV
201
        if err != nil {
×
202
                return err
×
203
        }
×
204

UNCOV
205
        return WriteElements(w,
×
UNCOV
206
                u.Hint,
×
UNCOV
207
                u.EncryptedBlob,
×
UNCOV
208
        )
×
209
}
210

211
// Decode reads a CommittedUpdateBody from the passed io.Reader.
UNCOV
212
func (u *CommittedUpdateBody) Decode(r io.Reader) error {
×
UNCOV
213
        err := u.BackupID.Decode(r)
×
UNCOV
214
        if err != nil {
×
215
                return err
×
216
        }
×
217

UNCOV
218
        return ReadElements(r,
×
UNCOV
219
                &u.Hint,
×
UNCOV
220
                &u.EncryptedBlob,
×
UNCOV
221
        )
×
222
}
223

224
// SessionIDSize is 33-bytes; it is a serialized, compressed public key.
225
const SessionIDSize = 33
226

227
// SessionID is created from the remote public key of a client, and serves as a
228
// unique identifier and authentication for sending state updates.
229
type SessionID [SessionIDSize]byte
230

231
// String returns a hex encoding of the session id.
UNCOV
232
func (s SessionID) String() string {
×
UNCOV
233
        return hex.EncodeToString(s[:])
×
UNCOV
234
}
×
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