• 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

75.0
/watchtower/wtdb/session_info.go
1
package wtdb
2

3
import (
4
        "errors"
5
        "io"
6

7
        "github.com/lightningnetwork/lnd/watchtower/blob"
8
        "github.com/lightningnetwork/lnd/watchtower/wtpolicy"
9
)
10

11
var (
12
        // ErrSessionNotFound is returned when querying by session id for a
13
        // session that does not exist.
14
        ErrSessionNotFound = errors.New("session not found in db")
15

16
        // ErrSessionAlreadyExists signals that a session creation failed
17
        // because a session with the same session id already exists.
18
        ErrSessionAlreadyExists = errors.New("session already exists")
19

20
        // ErrUpdateOutOfOrder is returned when the sequence number is not equal
21
        // to the server's LastApplied+1.
22
        ErrUpdateOutOfOrder = errors.New("update sequence number is not " +
23
                "sequential")
24

25
        // ErrLastAppliedReversion is returned when the client echos a
26
        // last-applied value that is less than it claimed in a prior update.
27
        ErrLastAppliedReversion = errors.New("update last applied must be " +
28
                "non-decreasing")
29

30
        // ErrSeqNumAlreadyApplied is returned when the client sends a sequence
31
        // number for which they already claim to have an ACK.
32
        ErrSeqNumAlreadyApplied = errors.New("update sequence number has " +
33
                "already been applied")
34

35
        // ErrSessionConsumed is returned if the client tries to send a sequence
36
        // number larger than the session's max number of updates.
37
        ErrSessionConsumed = errors.New("all session updates have been " +
38
                "consumed")
39
)
40

41
// SessionInfo holds the negotiated session parameters for single session id,
42
// and handles the acceptance and validation of state updates sent by the
43
// client.
44
type SessionInfo struct {
45
        // ID is the remote public key of the watchtower client.
46
        ID SessionID
47

48
        // Policy holds the negotiated session parameters.
49
        Policy wtpolicy.Policy
50

51
        // LastApplied the sequence number of the last successful state update.
52
        LastApplied uint16
53

54
        // ClientLastApplied the last last-applied the client has echoed back.
55
        ClientLastApplied uint16
56

57
        // RewardAddress the address that the tower's reward will be deposited
58
        // to if a sweep transaction confirms.
59
        RewardAddress []byte
60

61
        // TODO(conner): store client metrics, DOS score, etc
62
}
63

64
// Encode serializes the session info to the given io.Writer.
65
func (s *SessionInfo) Encode(w io.Writer) error {
3✔
66
        return WriteElements(w,
3✔
67
                s.ID,
3✔
68
                s.Policy,
3✔
69
                s.LastApplied,
3✔
70
                s.ClientLastApplied,
3✔
71
                s.RewardAddress,
3✔
72
        )
3✔
73
}
3✔
74

75
// Decode deserializes the session info from the given io.Reader.
76
func (s *SessionInfo) Decode(r io.Reader) error {
3✔
77
        return ReadElements(r,
3✔
78
                &s.ID,
3✔
79
                &s.Policy,
3✔
80
                &s.LastApplied,
3✔
81
                &s.ClientLastApplied,
3✔
82
                &s.RewardAddress,
3✔
83
        )
3✔
84
}
3✔
85

86
// AcceptUpdateSequence validates that a state update's sequence number and last
87
// applied are valid given our past history with the client. These checks ensure
88
// that clients are properly in sync and following the update protocol properly.
89
// If validation is successful, the receiver's LastApplied and ClientLastApplied
90
// are updated with the latest values presented by the client. Any errors
91
// returned from this method are converted into an appropriate
92
// wtwire.StateUpdateCode.
93
func (s *SessionInfo) AcceptUpdateSequence(seqNum, lastApplied uint16) error {
3✔
94
        switch {
3✔
95

96
        // Client already claims to have an ACK for this seqnum.
UNCOV
97
        case seqNum <= lastApplied:
×
UNCOV
98
                return ErrSeqNumAlreadyApplied
×
99

100
        // Client echos a last applied that is lower than previously sent.
UNCOV
101
        case lastApplied < s.ClientLastApplied:
×
UNCOV
102
                return ErrLastAppliedReversion
×
103

104
        // Client update exceeds capacity of session.
UNCOV
105
        case seqNum > s.Policy.MaxUpdates:
×
UNCOV
106
                return ErrSessionConsumed
×
107

108
        // Client update does not match our expected next seqnum.
UNCOV
109
        case seqNum != s.LastApplied && seqNum != s.LastApplied+1:
×
UNCOV
110
                return ErrUpdateOutOfOrder
×
111
        }
112

113
        s.LastApplied = seqNum
3✔
114
        s.ClientLastApplied = lastApplied
3✔
115

3✔
116
        return nil
3✔
117
}
118

119
// Match is returned in response to a database query for a breach hints
120
// contained in a particular block. The match encapsulates all data required to
121
// properly decrypt a client's encrypted blob, and pursue action on behalf of
122
// the victim by reconstructing the justice transaction and broadcasting it to
123
// the network.
124
//
125
// NOTE: It is possible for a match to cause a false positive, since they are
126
// matched on a prefix of the txid. In such an event, the likely behavior is
127
// that the payload will fail to decrypt.
128
type Match struct {
129
        // ID is the session id of the client who uploaded the state update.
130
        ID SessionID
131

132
        // SeqNum is the session sequence number occupied by the client's state
133
        // update. Together with ID, this allows the tower to derive the
134
        // appropriate nonce for decryption.
135
        SeqNum uint16
136

137
        // Hint is the breach hint that triggered the match.
138
        Hint blob.BreachHint
139

140
        // EncryptedBlob is the encrypted payload containing the justice kit
141
        // uploaded by the client.
142
        EncryptedBlob []byte
143

144
        // SessionInfo is the contract negotiated between tower and client, that
145
        // provides input parameters such as fee rate, reward rate, and reward
146
        // address when attempting to reconstruct the justice transaction.
147
        SessionInfo *SessionInfo
148
}
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