Skip to content

Commit 15f0888

Browse files
committed
routing: fix mission control migration
This commit is temporary and demonstrates a panic. To be squashed with the following commit.
1 parent aa9abb3 commit 15f0888

File tree

2 files changed

+121
-92
lines changed

2 files changed

+121
-92
lines changed

channeldb/migration32/migration_test.go

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,32 @@ var (
118118
},
119119
}
120120

121+
resultOld3 = paymentResultOld{
122+
id: 3,
123+
timeFwd: time.Unix(0, 4),
124+
timeReply: time.Unix(0, 7),
125+
success: false,
126+
failure: nil,
127+
failureSourceIdx: &failureIndex,
128+
route: &Route{
129+
TotalTimeLock: 101,
130+
TotalAmount: 401,
131+
SourcePubKey: testPub2,
132+
Hops: []*Hop{
133+
{
134+
PubKeyBytes: testPub,
135+
ChannelID: 800,
136+
OutgoingTimeLock: 4,
137+
AmtToForward: 4,
138+
BlindingPoint: pubkey,
139+
EncryptedData: []byte{1, 2, 3},
140+
CustomRecords: customRecord,
141+
TotalAmtMsat: 600,
142+
},
143+
},
144+
},
145+
}
146+
121147
//nolint:ll
122148
resultNew1Hop1 = &mcHop{
123149
channelID: tlv.NewPrimitiveRecord[tlv.TlvType0, uint64](100),
@@ -182,7 +208,7 @@ var (
182208
),
183209
failure: tlv.SomeRecordT(
184210
tlv.NewRecordT[tlv.TlvType3](
185-
*newPaymentFailure(
211+
newPaymentFailure(
186212
&failureIndex,
187213
&lnwire.FailFeeInsufficient{},
188214
),
@@ -217,6 +243,31 @@ var (
217243
}),
218244
}),
219245
}
246+
247+
//nolint:ll
248+
resultNew3 = paymentResultNew{
249+
id: 3,
250+
timeFwd: tlv.NewPrimitiveRecord[tlv.TlvType0, uint64](
251+
uint64(time.Unix(0, 4).UnixNano()),
252+
),
253+
timeReply: tlv.NewPrimitiveRecord[tlv.TlvType1, uint64](
254+
uint64(time.Unix(0, 7).UnixNano()),
255+
),
256+
failure: tlv.SomeRecordT(
257+
tlv.NewRecordT[tlv.TlvType3](
258+
newPaymentFailure(
259+
&failureIndex, nil,
260+
),
261+
),
262+
),
263+
route: tlv.NewRecordT[tlv.TlvType2](mcRoute{
264+
sourcePubKey: tlv.NewRecordT[tlv.TlvType0](testPub2),
265+
totalAmount: tlv.NewRecordT[tlv.TlvType1, lnwire.MilliSatoshi](401),
266+
hops: tlv.NewRecordT[tlv.TlvType2](mcHops{
267+
resultNew2Hop1,
268+
}),
269+
}),
270+
}
220271
)
221272

222273
// TestMigrateMCRouteSerialisation tests that the MigrateMCRouteSerialisation
@@ -225,10 +276,10 @@ var (
225276
func TestMigrateMCRouteSerialisation(t *testing.T) {
226277
var (
227278
resultsOld = []*paymentResultOld{
228-
&resultOld1, &resultOld2,
279+
&resultOld1, &resultOld2, &resultOld3,
229280
}
230281
expectedResultsNew = []*paymentResultNew{
231-
&resultNew1, &resultNew2,
282+
&resultNew1, &resultNew2, &resultNew3,
232283
}
233284
)
234285

channeldb/migration32/mission_control_store.go

Lines changed: 67 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,12 @@ func deserializeOldResult(k, v []byte) (*paymentResultOld, error) {
9393

9494
// convertPaymentResult converts a paymentResultOld to a paymentResultNew.
9595
func convertPaymentResult(old *paymentResultOld) *paymentResultNew {
96-
var failure *paymentFailure
96+
var failure fn.Option[paymentFailure]
9797
if !old.success {
98-
failure = newPaymentFailure(old.failureSourceIdx, old.failure)
98+
failure = fn.Some(newPaymentFailure(
99+
old.failureSourceIdx,
100+
old.failure,
101+
))
99102
}
100103

101104
return newPaymentResult(
@@ -106,7 +109,7 @@ func convertPaymentResult(old *paymentResultOld) *paymentResultNew {
106109

107110
// newPaymentResult constructs a new paymentResult.
108111
func newPaymentResult(id uint64, rt *mcRoute, timeFwd, timeReply time.Time,
109-
failure *paymentFailure) *paymentResultNew {
112+
failure fn.Option[paymentFailure]) *paymentResultNew {
110113

111114
result := &paymentResultNew{
112115
id: id,
@@ -119,11 +122,11 @@ func newPaymentResult(id uint64, rt *mcRoute, timeFwd, timeReply time.Time,
119122
route: tlv.NewRecordT[tlv.TlvType2](*rt),
120123
}
121124

122-
if failure != nil {
125+
failure.WhenSome(func(f paymentFailure) {
123126
result.failure = tlv.SomeRecordT(
124-
tlv.NewRecordT[tlv.TlvType3](*failure),
127+
tlv.NewRecordT[tlv.TlvType3](f),
125128
)
126-
}
129+
})
127130

128131
return result
129132
}
@@ -142,33 +145,49 @@ type paymentResultNew struct {
142145
failure tlv.OptionalRecordT[tlv.TlvType3, paymentFailure]
143146
}
144147

145-
// paymentFailure represents the presence of a payment failure. It may or may
146-
// not include additional information about said failure.
147-
type paymentFailure struct {
148-
info tlv.OptionalRecordT[tlv.TlvType0, paymentFailureInfo]
149-
}
150-
151148
// newPaymentFailure constructs a new paymentFailure struct. If the source
152149
// index is nil, then an empty paymentFailure is returned. This represents a
153150
// failure with unknown details. Otherwise, the index and failure message are
154151
// used to populate the info field of the paymentFailure.
155152
func newPaymentFailure(sourceIdx *int,
156-
failureMsg lnwire.FailureMessage) *paymentFailure {
153+
failureMsg lnwire.FailureMessage) paymentFailure {
157154

155+
// If we can't identify a failure source, we also won't have a decrypted
156+
// failure message. In this case we return an empty payment failure.
158157
if sourceIdx == nil {
159-
return &paymentFailure{}
158+
return paymentFailure{}
160159
}
161160

162-
info := paymentFailureInfo{
163-
sourceIdx: tlv.NewPrimitiveRecord[tlv.TlvType0](
164-
uint8(*sourceIdx),
161+
info := paymentFailure{
162+
sourceIdx: tlv.SomeRecordT(
163+
tlv.NewPrimitiveRecord[tlv.TlvType0](
164+
uint8(*sourceIdx),
165+
),
165166
),
166-
msg: tlv.NewRecordT[tlv.TlvType1](failureMessage{failureMsg}),
167167
}
168168

169-
return &paymentFailure{
170-
info: tlv.SomeRecordT(tlv.NewRecordT[tlv.TlvType0](info)),
169+
if failureMsg != nil {
170+
info.msg = tlv.SomeRecordT(
171+
tlv.NewRecordT[tlv.TlvType1](
172+
failureMessage{failureMsg},
173+
),
174+
)
171175
}
176+
177+
return info
178+
}
179+
180+
// paymentFailure holds additional information about a payment failure.
181+
type paymentFailure struct {
182+
// sourceIdx is the hop the error was reported from. In order to be able
183+
// to decrypt the error message, we need to know the source, which is
184+
// why an error message can only be present if the source is known.
185+
sourceIdx tlv.OptionalRecordT[tlv.TlvType0, uint8]
186+
187+
// msg is the error why a payment failed. If we identify the failure of
188+
// a certain hop at the above index, but aren't able to decode the
189+
// failure message we indicate this by not setting this field.
190+
msg tlv.OptionalRecordT[tlv.TlvType1, failureMessage]
172191
}
173192

174193
// Record returns a TLV record that can be used to encode/decode a
@@ -194,14 +213,27 @@ func (r *paymentFailure) Record() tlv.Record {
194213
func encodePaymentFailure(w io.Writer, val interface{}, _ *[8]byte) error {
195214
if v, ok := val.(*paymentFailure); ok {
196215
var recordProducers []tlv.RecordProducer
197-
v.info.WhenSome(
198-
func(r tlv.RecordT[tlv.TlvType0, paymentFailureInfo]) {
199-
recordProducers = append(recordProducers, &r)
216+
217+
v.sourceIdx.WhenSome(
218+
func(r tlv.RecordT[tlv.TlvType0, uint8]) {
219+
recordProducers = append(
220+
recordProducers, &r,
221+
)
222+
},
223+
)
224+
225+
v.msg.WhenSome(
226+
func(r tlv.RecordT[tlv.TlvType1, failureMessage]) {
227+
recordProducers = append(
228+
recordProducers, &r,
229+
)
200230
},
201231
)
202232

203233
return lnwire.EncodeRecordsTo(
204-
w, lnwire.ProduceRecordsSorted(recordProducers...),
234+
w, lnwire.ProduceRecordsSorted(
235+
recordProducers...,
236+
),
205237
)
206238
}
207239

@@ -210,81 +242,27 @@ func encodePaymentFailure(w io.Writer, val interface{}, _ *[8]byte) error {
210242

211243
func decodePaymentFailure(r io.Reader, val interface{}, _ *[8]byte,
212244
l uint64) error {
213-
214245
if v, ok := val.(*paymentFailure); ok {
215246
var h paymentFailure
216247

217-
info := tlv.ZeroRecordT[tlv.TlvType0, paymentFailureInfo]()
248+
sourceIdx := tlv.ZeroRecordT[tlv.TlvType0, uint8]()
249+
msg := tlv.ZeroRecordT[tlv.TlvType1, failureMessage]()
250+
218251
typeMap, err := lnwire.DecodeRecords(
219-
r, lnwire.ProduceRecordsSorted(&info)...,
252+
r,
253+
lnwire.ProduceRecordsSorted(&sourceIdx, &msg)...,
220254
)
255+
221256
if err != nil {
222257
return err
223258
}
224259

225-
if _, ok := typeMap[h.info.TlvType()]; ok {
226-
h.info = tlv.SomeRecordT(info)
260+
if _, ok := typeMap[h.sourceIdx.TlvType()]; ok {
261+
h.sourceIdx = tlv.SomeRecordT(sourceIdx)
227262
}
228263

229-
*v = h
230-
231-
return nil
232-
}
233-
234-
return tlv.NewTypeForDecodingErr(val, "routing.paymentFailure", l, l)
235-
}
236-
237-
// paymentFailureInfo holds additional information about a payment failure.
238-
type paymentFailureInfo struct {
239-
sourceIdx tlv.RecordT[tlv.TlvType0, uint8]
240-
msg tlv.RecordT[tlv.TlvType1, failureMessage]
241-
}
242-
243-
// Record returns a TLV record that can be used to encode/decode a
244-
// paymentFailureInfo to/from a TLV stream.
245-
func (r *paymentFailureInfo) Record() tlv.Record {
246-
recordSize := func() uint64 {
247-
var (
248-
b bytes.Buffer
249-
buf [8]byte
250-
)
251-
if err := encodePaymentFailureInfo(&b, r, &buf); err != nil {
252-
panic(err)
253-
}
254-
255-
return uint64(len(b.Bytes()))
256-
}
257-
258-
return tlv.MakeDynamicRecord(
259-
0, r, recordSize, encodePaymentFailureInfo,
260-
decodePaymentFailureInfo,
261-
)
262-
}
263-
264-
func encodePaymentFailureInfo(w io.Writer, val interface{}, _ *[8]byte) error {
265-
if v, ok := val.(*paymentFailureInfo); ok {
266-
return lnwire.EncodeRecordsTo(
267-
w, lnwire.ProduceRecordsSorted(
268-
&v.sourceIdx, &v.msg,
269-
),
270-
)
271-
}
272-
273-
return tlv.NewTypeForEncodingErr(val, "routing.paymentFailureInfo")
274-
}
275-
276-
func decodePaymentFailureInfo(r io.Reader, val interface{}, _ *[8]byte,
277-
l uint64) error {
278-
279-
if v, ok := val.(*paymentFailureInfo); ok {
280-
var h paymentFailureInfo
281-
282-
_, err := lnwire.DecodeRecords(
283-
r,
284-
lnwire.ProduceRecordsSorted(&h.sourceIdx, &h.msg)...,
285-
)
286-
if err != nil {
287-
return err
264+
if _, ok := typeMap[h.msg.TlvType()]; ok {
265+
h.msg = tlv.SomeRecordT(msg)
288266
}
289267

290268
*v = h
@@ -293,7 +271,7 @@ func decodePaymentFailureInfo(r io.Reader, val interface{}, _ *[8]byte,
293271
}
294272

295273
return tlv.NewTypeForDecodingErr(
296-
val, "routing.paymentFailureInfo", l, l,
274+
val, "routing.paymentFailure", l, l,
297275
)
298276
}
299277

0 commit comments

Comments
 (0)