forked from lightningnetwork/lnd
/
session_info.go
148 lines (120 loc) · 4.87 KB
/
session_info.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package wtdb
import (
"errors"
"io"
"github.com/John-Tonny/lnd/watchtower/blob"
"github.com/John-Tonny/lnd/watchtower/wtpolicy"
)
var (
// ErrSessionNotFound is returned when querying by session id for a
// session that does not exist.
ErrSessionNotFound = errors.New("session not found in db")
// ErrSessionAlreadyExists signals that a session creation failed
// because a session with the same session id already exists.
ErrSessionAlreadyExists = errors.New("session already exists")
// ErrUpdateOutOfOrder is returned when the sequence number is not equal
// to the server's LastApplied+1.
ErrUpdateOutOfOrder = errors.New("update sequence number is not " +
"sequential")
// ErrLastAppliedReversion is returned when the client echos a
// last-applied value that is less than it claimed in a prior update.
ErrLastAppliedReversion = errors.New("update last applied must be " +
"non-decreasing")
// ErrSeqNumAlreadyApplied is returned when the client sends a sequence
// number for which they already claim to have an ACK.
ErrSeqNumAlreadyApplied = errors.New("update sequence number has " +
"already been applied")
// ErrSessionConsumed is returned if the client tries to send a sequence
// number larger than the session's max number of updates.
ErrSessionConsumed = errors.New("all session updates have been " +
"consumed")
)
// SessionInfo holds the negotiated session parameters for single session id,
// and handles the acceptance and validation of state updates sent by the
// client.
type SessionInfo struct {
// ID is the remote public key of the watchtower client.
ID SessionID
// Policy holds the negotiated session parameters.
Policy wtpolicy.Policy
// LastApplied the sequence number of the last successful state update.
LastApplied uint16
// ClientLastApplied the last last-applied the client has echoed back.
ClientLastApplied uint16
// RewardAddress the address that the tower's reward will be deposited
// to if a sweep transaction confirms.
RewardAddress []byte
// TODO(conner): store client metrics, DOS score, etc
}
// Encode serializes the session info to the given io.Writer.
func (s *SessionInfo) Encode(w io.Writer) error {
return WriteElements(w,
s.ID,
s.Policy,
s.LastApplied,
s.ClientLastApplied,
s.RewardAddress,
)
}
// Decode deserializes the session infor from the given io.Reader.
func (s *SessionInfo) Decode(r io.Reader) error {
return ReadElements(r,
&s.ID,
&s.Policy,
&s.LastApplied,
&s.ClientLastApplied,
&s.RewardAddress,
)
}
// AcceptUpdateSequence validates that a state update's sequence number and last
// applied are valid given our past history with the client. These checks ensure
// that clients are properly in sync and following the update protocol properly.
// If validation is successful, the receiver's LastApplied and ClientLastApplied
// are updated with the latest values presented by the client. Any errors
// returned from this method are converted into an appropriate
// wtwire.StateUpdateCode.
func (s *SessionInfo) AcceptUpdateSequence(seqNum, lastApplied uint16) error {
switch {
// Client already claims to have an ACK for this seqnum.
case seqNum <= lastApplied:
return ErrSeqNumAlreadyApplied
// Client echos a last applied that is lower than previously sent.
case lastApplied < s.ClientLastApplied:
return ErrLastAppliedReversion
// Client update exceeds capacity of session.
case seqNum > s.Policy.MaxUpdates:
return ErrSessionConsumed
// Client update does not match our expected next seqnum.
case seqNum != s.LastApplied && seqNum != s.LastApplied+1:
return ErrUpdateOutOfOrder
}
s.LastApplied = seqNum
s.ClientLastApplied = lastApplied
return nil
}
// Match is returned in response to a database query for a breach hints
// contained in a particular block. The match encapsulates all data required to
// properly decrypt a client's encrypted blob, and pursue action on behalf of
// the victim by reconstructing the justice transaction and broadcasting it to
// the network.
//
// NOTE: It is possible for a match to cause a false positive, since they are
// matched on a prefix of the txid. In such an event, the likely behavior is
// that the payload will fail to decrypt.
type Match struct {
// ID is the session id of the client who uploaded the state update.
ID SessionID
// SeqNum is the session sequence number occupied by the client's state
// update. Together with ID, this allows the tower to derive the
// appropriate nonce for decryption.
SeqNum uint16
// Hint is the breach hint that triggered the match.
Hint blob.BreachHint
// EncryptedBlob is the encrypted payload containing the justice kit
// uploaded by the client.
EncryptedBlob []byte
// SessionInfo is the contract negotiated between tower and client, that
// provides input parameters such as fee rate, reward rate, and reward
// address when attempting to reconstruct the justice transaction.
SessionInfo *SessionInfo
}