• 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/migration1/codec.go
1
package migration1
2

3
import (
4
        "encoding/binary"
5
        "io"
6

7
        "github.com/lightningnetwork/lnd/channeldb"
8
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
9
        "github.com/lightningnetwork/lnd/watchtower/blob"
10
        "github.com/lightningnetwork/lnd/watchtower/wtpolicy"
11
)
12

13
// SessionIDSize is 33-bytes; it is a serialized, compressed public key.
14
const SessionIDSize = 33
15

16
// UnknownElementType is an alias for channeldb.UnknownElementType.
17
type UnknownElementType = channeldb.UnknownElementType
18

19
// SessionID is created from the remote public key of a client, and serves as a
20
// unique identifier and authentication for sending state updates.
21
type SessionID [SessionIDSize]byte
22

23
// TowerID is a unique 64-bit identifier allocated to each unique watchtower.
24
// This allows the client to conserve on-disk space by not needing to always
25
// reference towers by their pubkey.
26
type TowerID uint64
27

28
// Bytes encodes a TowerID into an 8-byte slice in big-endian byte order.
UNCOV
29
func (id TowerID) Bytes() []byte {
×
UNCOV
30
        var buf [8]byte
×
UNCOV
31
        binary.BigEndian.PutUint64(buf[:], uint64(id))
×
UNCOV
32
        return buf[:]
×
UNCOV
33
}
×
34

35
// ClientSession encapsulates a SessionInfo returned from a successful
36
// session negotiation, and also records the tower and ephemeral secret used for
37
// communicating with the tower.
38
type ClientSession struct {
39
        // ID is the client's public key used when authenticating with the
40
        // tower.
41
        ID SessionID
42
        ClientSessionBody
43
}
44

45
// CSessionStatus is a bit-field representing the possible statuses of
46
// ClientSessions.
47
type CSessionStatus uint8
48

49
type ClientSessionBody struct {
50
        // SeqNum is the next unallocated sequence number that can be sent to
51
        // the tower.
52
        SeqNum uint16
53

54
        // TowerLastApplied the last last-applied the tower has echoed back.
55
        TowerLastApplied uint16
56

57
        // TowerID is the unique, db-assigned identifier that references the
58
        // Tower with which the session is negotiated.
59
        TowerID TowerID
60

61
        // KeyIndex is the index of key locator used to derive the client's
62
        // session key so that it can authenticate with the tower to update its
63
        // session. In order to rederive the private key, the key locator should
64
        // use the keychain.KeyFamilyTowerSession key family.
65
        KeyIndex uint32
66

67
        // Policy holds the negotiated session parameters.
68
        Policy wtpolicy.Policy
69

70
        // Status indicates the current state of the ClientSession.
71
        Status CSessionStatus
72

73
        // RewardPkScript is the pkscript that the tower's reward will be
74
        // deposited to if a sweep transaction confirms and the sessions
75
        // specifies a reward output.
76
        RewardPkScript []byte
77
}
78

79
// Encode writes a ClientSessionBody to the passed io.Writer.
UNCOV
80
func (s *ClientSessionBody) Encode(w io.Writer) error {
×
UNCOV
81
        return WriteElements(w,
×
UNCOV
82
                s.SeqNum,
×
UNCOV
83
                s.TowerLastApplied,
×
UNCOV
84
                uint64(s.TowerID),
×
UNCOV
85
                s.KeyIndex,
×
UNCOV
86
                uint8(s.Status),
×
UNCOV
87
                s.Policy,
×
UNCOV
88
                s.RewardPkScript,
×
UNCOV
89
        )
×
UNCOV
90
}
×
91

92
// Decode reads a ClientSessionBody from the passed io.Reader.
UNCOV
93
func (s *ClientSessionBody) Decode(r io.Reader) error {
×
UNCOV
94
        var (
×
UNCOV
95
                towerID uint64
×
UNCOV
96
                status  uint8
×
UNCOV
97
        )
×
UNCOV
98
        err := ReadElements(r,
×
UNCOV
99
                &s.SeqNum,
×
UNCOV
100
                &s.TowerLastApplied,
×
UNCOV
101
                &towerID,
×
UNCOV
102
                &s.KeyIndex,
×
UNCOV
103
                &status,
×
UNCOV
104
                &s.Policy,
×
UNCOV
105
                &s.RewardPkScript,
×
UNCOV
106
        )
×
UNCOV
107
        if err != nil {
×
108
                return err
×
109
        }
×
110

UNCOV
111
        s.TowerID = TowerID(towerID)
×
UNCOV
112
        s.Status = CSessionStatus(status)
×
UNCOV
113

×
UNCOV
114
        return nil
×
115
}
116

117
// WriteElements serializes a variadic list of elements into the given
118
// io.Writer.
UNCOV
119
func WriteElements(w io.Writer, elements ...interface{}) error {
×
UNCOV
120
        for _, element := range elements {
×
UNCOV
121
                if err := WriteElement(w, element); err != nil {
×
122
                        return err
×
123
                }
×
124
        }
125

UNCOV
126
        return nil
×
127
}
128

129
// WriteElement serializes a single element into the provided io.Writer.
UNCOV
130
func WriteElement(w io.Writer, element interface{}) error {
×
UNCOV
131
        err := channeldb.WriteElement(w, element)
×
UNCOV
132
        switch {
×
133
        // Known to channeldb codec.
UNCOV
134
        case err == nil:
×
UNCOV
135
                return nil
×
136

137
        // Fail if error is not UnknownElementType.
UNCOV
138
        default:
×
UNCOV
139
                if _, ok := err.(UnknownElementType); !ok {
×
140
                        return err
×
141
                }
×
142
        }
143

144
        // Process any wtdb-specific extensions to the codec.
UNCOV
145
        switch e := element.(type) {
×
146
        case SessionID:
×
147
                if _, err := w.Write(e[:]); err != nil {
×
148
                        return err
×
149
                }
×
150

151
        case blob.BreachHint:
×
152
                if _, err := w.Write(e[:]); err != nil {
×
153
                        return err
×
154
                }
×
155

UNCOV
156
        case wtpolicy.Policy:
×
UNCOV
157
                return channeldb.WriteElements(w,
×
UNCOV
158
                        uint16(e.BlobType),
×
UNCOV
159
                        e.MaxUpdates,
×
UNCOV
160
                        e.RewardBase,
×
UNCOV
161
                        e.RewardRate,
×
UNCOV
162
                        uint64(e.SweepFeeRate),
×
UNCOV
163
                )
×
164

165
        // Type is still unknown to wtdb extensions, fail.
166
        default:
×
167
                return channeldb.NewUnknownElementType(
×
168
                        "WriteElement", element,
×
169
                )
×
170
        }
171

172
        return nil
×
173
}
174

175
// ReadElements deserializes the provided io.Reader into a variadic list of
176
// target elements.
UNCOV
177
func ReadElements(r io.Reader, elements ...interface{}) error {
×
UNCOV
178
        for _, element := range elements {
×
UNCOV
179
                if err := ReadElement(r, element); err != nil {
×
180
                        return err
×
181
                }
×
182
        }
183

UNCOV
184
        return nil
×
185
}
186

187
// ReadElement deserializes a single element from the provided io.Reader.
UNCOV
188
func ReadElement(r io.Reader, element interface{}) error {
×
UNCOV
189
        err := channeldb.ReadElement(r, element)
×
UNCOV
190
        switch {
×
191
        // Known to channeldb codec.
UNCOV
192
        case err == nil:
×
UNCOV
193
                return nil
×
194

195
        // Fail if error is not UnknownElementType.
UNCOV
196
        default:
×
UNCOV
197
                if _, ok := err.(UnknownElementType); !ok {
×
198
                        return err
×
199
                }
×
200
        }
201

202
        // Process any wtdb-specific extensions to the codec.
UNCOV
203
        switch e := element.(type) {
×
204
        case *SessionID:
×
205
                if _, err := io.ReadFull(r, e[:]); err != nil {
×
206
                        return err
×
207
                }
×
208

209
        case *blob.BreachHint:
×
210
                if _, err := io.ReadFull(r, e[:]); err != nil {
×
211
                        return err
×
212
                }
×
213

UNCOV
214
        case *wtpolicy.Policy:
×
UNCOV
215
                var (
×
UNCOV
216
                        blobType     uint16
×
UNCOV
217
                        sweepFeeRate uint64
×
UNCOV
218
                )
×
UNCOV
219
                err := channeldb.ReadElements(r,
×
UNCOV
220
                        &blobType,
×
UNCOV
221
                        &e.MaxUpdates,
×
UNCOV
222
                        &e.RewardBase,
×
UNCOV
223
                        &e.RewardRate,
×
UNCOV
224
                        &sweepFeeRate,
×
UNCOV
225
                )
×
UNCOV
226
                if err != nil {
×
227
                        return err
×
228
                }
×
229

UNCOV
230
                e.BlobType = blob.Type(blobType)
×
UNCOV
231
                e.SweepFeeRate = chainfee.SatPerKWeight(sweepFeeRate)
×
232

233
        // Type is still unknown to wtdb extensions, fail.
234
        default:
×
235
                return channeldb.NewUnknownElementType(
×
236
                        "ReadElement", element,
×
237
                )
×
238
        }
239

UNCOV
240
        return nil
×
241
}
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