forked from lightningnetwork/lnd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathresolution_store.go
202 lines (164 loc) · 5.08 KB
/
resolution_store.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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package htlcswitch
import (
"bytes"
"io"
"github.com/go-errors/errors"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/lnwire"
)
var (
// resBucketKey is used for the root level bucket that stores the
// CircuitKey -> ResolutionMsg mapping.
resBucketKey = []byte("resolution-store-bucket-key")
// errResMsgNotFound is used to let callers know that the resolution
// message was not found for the given CircuitKey. This is used in the
// checkResolutionMsg function.
errResMsgNotFound = errors.New("resolution message not found")
)
// resolutionStore contains ResolutionMsgs received from the contractcourt. The
// Switch deletes these from the store when the underlying circuit has been
// removed via DeleteCircuits. If the circuit hasn't been deleted, the Switch
// will dispatch the ResolutionMsg to a link if this was a multi-hop HTLC or to
// itself if the Switch initiated the payment.
type resolutionStore struct {
backend kvdb.Backend
}
func newResolutionStore(db kvdb.Backend) *resolutionStore {
return &resolutionStore{
backend: db,
}
}
// addResolutionMsg persists a ResolutionMsg to the resolutionStore.
func (r *resolutionStore) addResolutionMsg(
resMsg *contractcourt.ResolutionMsg) error {
// The outKey will be the database key.
outKey := &CircuitKey{
ChanID: resMsg.SourceChan,
HtlcID: resMsg.HtlcIndex,
}
var resBuf bytes.Buffer
if err := serializeResolutionMsg(&resBuf, resMsg); err != nil {
return err
}
err := kvdb.Update(r.backend, func(tx kvdb.RwTx) error {
resBucket, err := tx.CreateTopLevelBucket(resBucketKey)
if err != nil {
return err
}
return resBucket.Put(outKey.Bytes(), resBuf.Bytes())
}, func() {})
if err != nil {
return err
}
return nil
}
// checkResolutionMsg returns nil if the resolution message is found in the
// store. It returns an error if no resolution message was found for the
// passed outKey or if a database error occurred.
func (r *resolutionStore) checkResolutionMsg(outKey *CircuitKey) error {
err := kvdb.View(r.backend, func(tx kvdb.RTx) error {
resBucket := tx.ReadBucket(resBucketKey)
if resBucket == nil {
// Return an error if the bucket doesn't exist.
return errResMsgNotFound
}
msg := resBucket.Get(outKey.Bytes())
if msg == nil {
// Return the not found error since no message exists
// for this CircuitKey.
return errResMsgNotFound
}
// Return nil to indicate that the message was found.
return nil
}, func() {})
if err != nil {
return err
}
return nil
}
// fetchAllResolutionMsg returns a slice of all stored ResolutionMsgs. This is
// used by the Switch on start-up.
func (r *resolutionStore) fetchAllResolutionMsg() (
[]*contractcourt.ResolutionMsg, error) {
var msgs []*contractcourt.ResolutionMsg
err := kvdb.View(r.backend, func(tx kvdb.RTx) error {
resBucket := tx.ReadBucket(resBucketKey)
if resBucket == nil {
return nil
}
return resBucket.ForEach(func(k, v []byte) error {
kr := bytes.NewReader(k)
outKey := &CircuitKey{}
if err := outKey.Decode(kr); err != nil {
return err
}
vr := bytes.NewReader(v)
resMsg, err := deserializeResolutionMsg(vr)
if err != nil {
return err
}
// Set the CircuitKey values on the ResolutionMsg.
resMsg.SourceChan = outKey.ChanID
resMsg.HtlcIndex = outKey.HtlcID
msgs = append(msgs, resMsg)
return nil
})
}, func() {
msgs = nil
})
if err != nil {
return nil, err
}
return msgs, nil
}
// deleteResolutionMsg removes a ResolutionMsg with the passed-in CircuitKey.
func (r *resolutionStore) deleteResolutionMsg(outKey *CircuitKey) error {
err := kvdb.Update(r.backend, func(tx kvdb.RwTx) error {
resBucket, err := tx.CreateTopLevelBucket(resBucketKey)
if err != nil {
return err
}
return resBucket.Delete(outKey.Bytes())
}, func() {})
return err
}
// serializeResolutionMsg writes part of a ResolutionMsg to the passed
// io.Writer.
func serializeResolutionMsg(w io.Writer,
resMsg *contractcourt.ResolutionMsg) error {
isFail := resMsg.Failure != nil
if err := channeldb.WriteElement(w, isFail); err != nil {
return err
}
// If this is a failure message, then we're done serializing.
if isFail {
return nil
}
// Else this is a settle message, and we need to write the preimage.
return channeldb.WriteElement(w, *resMsg.PreImage)
}
// deserializeResolutionMsg reads part of a ResolutionMsg from the passed
// io.Reader.
func deserializeResolutionMsg(r io.Reader) (*contractcourt.ResolutionMsg,
error) {
resMsg := &contractcourt.ResolutionMsg{}
var isFail bool
if err := channeldb.ReadElements(r, &isFail); err != nil {
return nil, err
}
// If a failure resolution msg was stored, set the Failure field.
if isFail {
failureMsg := &lnwire.FailPermanentChannelFailure{}
resMsg.Failure = failureMsg
return resMsg, nil
}
var preimage [32]byte
resMsg.PreImage = &preimage
// Else this is a settle resolution msg and we will read the preimage.
if err := channeldb.ReadElement(r, resMsg.PreImage); err != nil {
return nil, err
}
return resMsg, nil
}