Merge pull request #9770 from bitromortac/2504-mc-migration-fix

routing+migration: fix mission control migration with nil failure msg
This commit is contained in:
Oliver Gugger authored and GitHub committed 2025-05-02 14:22:59 +02:00
commit 334a7d1123
7 files changed
+234 -210

No files matched your search

+54 -3
View File
@@ -118,6 +118,32 @@ var (
}, },
} }
resultOld3 = paymentResultOld{
id: 3,
timeFwd: time.Unix(0, 4),
timeReply: time.Unix(0, 7),
success: false,
failure: nil,
failureSourceIdx: &failureIndex,
route: &Route{
TotalTimeLock: 101,
TotalAmount: 401,
SourcePubKey: testPub2,
Hops: []*Hop{
{
PubKeyBytes: testPub,
ChannelID: 800,
OutgoingTimeLock: 4,
AmtToForward: 4,
BlindingPoint: pubkey,
EncryptedData: []byte{1, 2, 3},
CustomRecords: customRecord,
TotalAmtMsat: 600,
},
},
},
}
//nolint:ll //nolint:ll
resultNew1Hop1 = &mcHop{ resultNew1Hop1 = &mcHop{
channelID: tlv.NewPrimitiveRecord[tlv.TlvType0, uint64](100), channelID: tlv.NewPrimitiveRecord[tlv.TlvType0, uint64](100),
@@ -182,7 +208,7 @@ var (
), ),
failure: tlv.SomeRecordT( failure: tlv.SomeRecordT(
tlv.NewRecordT[tlv.TlvType3]( tlv.NewRecordT[tlv.TlvType3](
*newPaymentFailure( newPaymentFailure(
&failureIndex, &failureIndex,
&lnwire.FailFeeInsufficient{}, &lnwire.FailFeeInsufficient{},
), ),
@@ -217,6 +243,31 @@ var (
}), }),
}), }),
} }
//nolint:ll
resultNew3 = paymentResultNew{
id: 3,
timeFwd: tlv.NewPrimitiveRecord[tlv.TlvType0, uint64](
uint64(time.Unix(0, 4).UnixNano()),
),
timeReply: tlv.NewPrimitiveRecord[tlv.TlvType1, uint64](
uint64(time.Unix(0, 7).UnixNano()),
),
failure: tlv.SomeRecordT(
tlv.NewRecordT[tlv.TlvType3](
newPaymentFailure(
&failureIndex, nil,
),
),
),
route: tlv.NewRecordT[tlv.TlvType2](mcRoute{
sourcePubKey: tlv.NewRecordT[tlv.TlvType0](testPub2),
totalAmount: tlv.NewRecordT[tlv.TlvType1, lnwire.MilliSatoshi](401),
hops: tlv.NewRecordT[tlv.TlvType2](mcHops{
resultNew2Hop1,
}),
}),
}
) )
// TestMigrateMCRouteSerialisation tests that the MigrateMCRouteSerialisation // TestMigrateMCRouteSerialisation tests that the MigrateMCRouteSerialisation
@@ -225,10 +276,10 @@ var (
func TestMigrateMCRouteSerialisation(t *testing.T) { func TestMigrateMCRouteSerialisation(t *testing.T) {
var ( var (
resultsOld = []*paymentResultOld{ resultsOld = []*paymentResultOld{
&resultOld1, &resultOld2, &resultOld1, &resultOld2, &resultOld3,
} }
expectedResultsNew = []*paymentResultNew{ expectedResultsNew = []*paymentResultNew{
&resultNew1, &resultNew2, &resultNew1, &resultNew2, &resultNew3,
} }
) )
+70 -92
View File
@@ -93,9 +93,12 @@ func deserializeOldResult(k, v []byte) (*paymentResultOld, error) {
// convertPaymentResult converts a paymentResultOld to a paymentResultNew. // convertPaymentResult converts a paymentResultOld to a paymentResultNew.
func convertPaymentResult(old *paymentResultOld) *paymentResultNew { func convertPaymentResult(old *paymentResultOld) *paymentResultNew {
var failure *paymentFailure var failure fn.Option[paymentFailure]
if !old.success { if !old.success {
failure = newPaymentFailure(old.failureSourceIdx, old.failure) failure = fn.Some(newPaymentFailure(
old.failureSourceIdx,
old.failure,
))
} }
return newPaymentResult( return newPaymentResult(
@@ -106,7 +109,7 @@ func convertPaymentResult(old *paymentResultOld) *paymentResultNew {
// newPaymentResult constructs a new paymentResult. // newPaymentResult constructs a new paymentResult.
func newPaymentResult(id uint64, rt *mcRoute, timeFwd, timeReply time.Time, func newPaymentResult(id uint64, rt *mcRoute, timeFwd, timeReply time.Time,
failure *paymentFailure) *paymentResultNew { failure fn.Option[paymentFailure]) *paymentResultNew {
result := &paymentResultNew{ result := &paymentResultNew{
id: id, id: id,
@@ -119,11 +122,11 @@ func newPaymentResult(id uint64, rt *mcRoute, timeFwd, timeReply time.Time,
route: tlv.NewRecordT[tlv.TlvType2](*rt), route: tlv.NewRecordT[tlv.TlvType2](*rt),
} }
if failure != nil { failure.WhenSome(func(f paymentFailure) {
result.failure = tlv.SomeRecordT( result.failure = tlv.SomeRecordT(
tlv.NewRecordT[tlv.TlvType3](*failure), tlv.NewRecordT[tlv.TlvType3](f),
) )
} })
return result return result
} }
@@ -142,33 +145,49 @@ type paymentResultNew struct {
failure tlv.OptionalRecordT[tlv.TlvType3, paymentFailure] failure tlv.OptionalRecordT[tlv.TlvType3, paymentFailure]
} }
// paymentFailure represents the presence of a payment failure. It may or may
// not include additional information about said failure.
type paymentFailure struct {
info tlv.OptionalRecordT[tlv.TlvType0, paymentFailureInfo]
}
// newPaymentFailure constructs a new paymentFailure struct. If the source // newPaymentFailure constructs a new paymentFailure struct. If the source
// index is nil, then an empty paymentFailure is returned. This represents a // index is nil, then an empty paymentFailure is returned. This represents a
// failure with unknown details. Otherwise, the index and failure message are // failure with unknown details. Otherwise, the index and failure message are
// used to populate the info field of the paymentFailure. // used to populate the info field of the paymentFailure.
func newPaymentFailure(sourceIdx *int, func newPaymentFailure(sourceIdx *int,
failureMsg lnwire.FailureMessage) *paymentFailure { failureMsg lnwire.FailureMessage) paymentFailure {
// If we can't identify a failure source, we also won't have a decrypted
// failure message. In this case we return an empty payment failure.
if sourceIdx == nil { if sourceIdx == nil {
return &paymentFailure{} return paymentFailure{}
} }
info := paymentFailureInfo{ info := paymentFailure{
sourceIdx: tlv.NewPrimitiveRecord[tlv.TlvType0]( sourceIdx: tlv.SomeRecordT(
uint8(*sourceIdx), tlv.NewPrimitiveRecord[tlv.TlvType0](
uint8(*sourceIdx),
),
), ),
msg: tlv.NewRecordT[tlv.TlvType1](failureMessage{failureMsg}),
} }
return &paymentFailure{ if failureMsg != nil {
info: tlv.SomeRecordT(tlv.NewRecordT[tlv.TlvType0](info)), info.msg = tlv.SomeRecordT(
tlv.NewRecordT[tlv.TlvType1](
failureMessage{failureMsg},
),
)
} }
return info
}
// paymentFailure holds additional information about a payment failure.
type paymentFailure struct {
// sourceIdx is the hop the error was reported from. In order to be able
// to decrypt the error message, we need to know the source, which is
// why an error message can only be present if the source is known.
sourceIdx tlv.OptionalRecordT[tlv.TlvType0, uint8]
// msg is the error why a payment failed. If we identify the failure of
// a certain hop at the above index, but aren't able to decode the
// failure message we indicate this by not setting this field.
msg tlv.OptionalRecordT[tlv.TlvType1, failureMessage]
} }
// Record returns a TLV record that can be used to encode/decode a // Record returns a TLV record that can be used to encode/decode a
@@ -194,14 +213,27 @@ func (r *paymentFailure) Record() tlv.Record {
func encodePaymentFailure(w io.Writer, val interface{}, _ *[8]byte) error { func encodePaymentFailure(w io.Writer, val interface{}, _ *[8]byte) error {
if v, ok := val.(*paymentFailure); ok { if v, ok := val.(*paymentFailure); ok {
var recordProducers []tlv.RecordProducer var recordProducers []tlv.RecordProducer
v.info.WhenSome(
func(r tlv.RecordT[tlv.TlvType0, paymentFailureInfo]) { v.sourceIdx.WhenSome(
recordProducers = append(recordProducers, &r) func(r tlv.RecordT[tlv.TlvType0, uint8]) {
recordProducers = append(
recordProducers, &r,
)
},
)
v.msg.WhenSome(
func(r tlv.RecordT[tlv.TlvType1, failureMessage]) {
recordProducers = append(
recordProducers, &r,
)
}, },
) )
return lnwire.EncodeRecordsTo( return lnwire.EncodeRecordsTo(
w, lnwire.ProduceRecordsSorted(recordProducers...), w, lnwire.ProduceRecordsSorted(
recordProducers...,
),
) )
} }
@@ -210,90 +242,36 @@ func encodePaymentFailure(w io.Writer, val interface{}, _ *[8]byte) error {
func decodePaymentFailure(r io.Reader, val interface{}, _ *[8]byte, func decodePaymentFailure(r io.Reader, val interface{}, _ *[8]byte,
l uint64) error { l uint64) error {
if v, ok := val.(*paymentFailure); ok { if v, ok := val.(*paymentFailure); ok {
var h paymentFailure var h paymentFailure
info := tlv.ZeroRecordT[tlv.TlvType0, paymentFailureInfo]() sourceIdx := tlv.ZeroRecordT[tlv.TlvType0, uint8]()
msg := tlv.ZeroRecordT[tlv.TlvType1, failureMessage]()
typeMap, err := lnwire.DecodeRecords( typeMap, err := lnwire.DecodeRecords(
r, lnwire.ProduceRecordsSorted(&info)...,
)
if err != nil {
return err
}
if _, ok := typeMap[h.info.TlvType()]; ok {
h.info = tlv.SomeRecordT(info)
}
*v = h
return nil
}
return tlv.NewTypeForDecodingErr(val, "routing.paymentFailure", l, l)
}
// paymentFailureInfo holds additional information about a payment failure.
type paymentFailureInfo struct {
sourceIdx tlv.RecordT[tlv.TlvType0, uint8]
msg tlv.RecordT[tlv.TlvType1, failureMessage]
}
// Record returns a TLV record that can be used to encode/decode a
// paymentFailureInfo to/from a TLV stream.
func (r *paymentFailureInfo) Record() tlv.Record {
recordSize := func() uint64 {
var (
b bytes.Buffer
buf [8]byte
)
if err := encodePaymentFailureInfo(&b, r, &buf); err != nil {
panic(err)
}
return uint64(len(b.Bytes()))
}
return tlv.MakeDynamicRecord(
0, r, recordSize, encodePaymentFailureInfo,
decodePaymentFailureInfo,
)
}
func encodePaymentFailureInfo(w io.Writer, val interface{}, _ *[8]byte) error {
if v, ok := val.(*paymentFailureInfo); ok {
return lnwire.EncodeRecordsTo(
w, lnwire.ProduceRecordsSorted(
&v.sourceIdx, &v.msg,
),
)
}
return tlv.NewTypeForEncodingErr(val, "routing.paymentFailureInfo")
}
func decodePaymentFailureInfo(r io.Reader, val interface{}, _ *[8]byte,
l uint64) error {
if v, ok := val.(*paymentFailureInfo); ok {
var h paymentFailureInfo
_, err := lnwire.DecodeRecords(
r, r,
lnwire.ProduceRecordsSorted(&h.sourceIdx, &h.msg)..., lnwire.ProduceRecordsSorted(&sourceIdx, &msg)...,
) )
if err != nil { if err != nil {
return err return err
} }
if _, ok := typeMap[h.sourceIdx.TlvType()]; ok {
h.sourceIdx = tlv.SomeRecordT(sourceIdx)
}
if _, ok := typeMap[h.msg.TlvType()]; ok {
h.msg = tlv.SomeRecordT(msg)
}
*v = h *v = h
return nil return nil
} }
return tlv.NewTypeForDecodingErr( return tlv.NewTypeForDecodingErr(
val, "routing.paymentFailureInfo", l, l, val, "routing.paymentFailure", l, l,
) )
} }
+6 -4
View File
@@ -484,10 +484,12 @@ the on going rate we'll permit.
## Database ## Database
* [Migrate the mission control * [Migrate the mission control
store](https://github.com/lightningnetwork/lnd/pull/8911) to use a more store](https://github.com/lightningnetwork/lnd/pull/8911) to use a more
minimal encoding for payment attempt routes as well as use [pure TLV minimal encoding for payment attempt routes as well as use [pure TLV
encoding](https://github.com/lightningnetwork/lnd/pull/9167). encoding](https://github.com/lightningnetwork/lnd/pull/9167). [A
fix](https://github.com/lightningnetwork/lnd/pull/9770) was added to handle
nil routing failure messages and the serialization was optimized.
* [Migrate the mission control * [Migrate the mission control
store](https://github.com/lightningnetwork/lnd/pull/9001) so that results are store](https://github.com/lightningnetwork/lnd/pull/9001) so that results are
+74 -94
View File
@@ -276,7 +276,7 @@ type paymentResult struct {
// newPaymentResult constructs a new paymentResult. // newPaymentResult constructs a new paymentResult.
func newPaymentResult(id uint64, rt *mcRoute, timeFwd, timeReply time.Time, func newPaymentResult(id uint64, rt *mcRoute, timeFwd, timeReply time.Time,
failure *paymentFailure) *paymentResult { failure fn.Option[paymentFailure]) *paymentResult {
result := &paymentResult{ result := &paymentResult{
id: id, id: id,
@@ -289,11 +289,13 @@ func newPaymentResult(id uint64, rt *mcRoute, timeFwd, timeReply time.Time,
route: tlv.NewRecordT[tlv.TlvType2](*rt), route: tlv.NewRecordT[tlv.TlvType2](*rt),
} }
if failure != nil { failure.WhenSome(
result.failure = tlv.SomeRecordT( func(f paymentFailure) {
tlv.NewRecordT[tlv.TlvType3](*failure), result.failure = tlv.SomeRecordT(
) tlv.NewRecordT[tlv.TlvType3](f),
} )
},
)
return result return result
} }
@@ -621,7 +623,7 @@ func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route,
result := newPaymentResult( result := newPaymentResult(
paymentID, extractMCRoute(rt), timestamp, timestamp, paymentID, extractMCRoute(rt), timestamp, timestamp,
newPaymentFailure(failureSourceIdx, failure), fn.Some(newPaymentFailure(failureSourceIdx, failure)),
) )
return m.processPaymentResult(result) return m.processPaymentResult(result)
@@ -635,7 +637,8 @@ func (m *MissionControl) ReportPaymentSuccess(paymentID uint64,
timestamp := m.cfg.clock.Now() timestamp := m.cfg.clock.Now()
result := newPaymentResult( result := newPaymentResult(
paymentID, extractMCRoute(rt), timestamp, timestamp, nil, paymentID, extractMCRoute(rt), timestamp, timestamp,
fn.None[paymentFailure](),
) )
_, err := m.processPaymentResult(result) _, err := m.processPaymentResult(result)
@@ -827,33 +830,49 @@ func (n *namespacedDB) purge() error {
}, func() {}) }, func() {})
} }
// paymentFailure represents the presence of a payment failure. It may or may
// not include additional information about said failure.
type paymentFailure struct {
info tlv.OptionalRecordT[tlv.TlvType0, paymentFailureInfo]
}
// newPaymentFailure constructs a new paymentFailure struct. If the source // newPaymentFailure constructs a new paymentFailure struct. If the source
// index is nil, then an empty paymentFailure is returned. This represents a // index is nil, then an empty paymentFailure is returned. This represents a
// failure with unknown details. Otherwise, the index and failure message are // failure with unknown details. Otherwise, the index and failure message are
// used to populate the info field of the paymentFailure. // used to populate the info field of the paymentFailure.
func newPaymentFailure(sourceIdx *int, func newPaymentFailure(sourceIdx *int,
failureMsg lnwire.FailureMessage) *paymentFailure { failureMsg lnwire.FailureMessage) paymentFailure {
// If we can't identify a failure source, we also won't have a decrypted
// failure message. In this case we return an empty payment failure.
if sourceIdx == nil { if sourceIdx == nil {
return &paymentFailure{} return paymentFailure{}
} }
info := paymentFailureInfo{ info := paymentFailure{
sourceIdx: tlv.NewPrimitiveRecord[tlv.TlvType0]( sourceIdx: tlv.SomeRecordT(
uint8(*sourceIdx), tlv.NewPrimitiveRecord[tlv.TlvType0](
uint8(*sourceIdx),
),
), ),
msg: tlv.NewRecordT[tlv.TlvType1](failureMessage{failureMsg}),
} }
return &paymentFailure{ if failureMsg != nil {
info: tlv.SomeRecordT(tlv.NewRecordT[tlv.TlvType0](info)), info.msg = tlv.SomeRecordT(
tlv.NewRecordT[tlv.TlvType1](
failureMessage{failureMsg},
),
)
} }
return info
}
// paymentFailure holds additional information about a payment failure.
type paymentFailure struct {
// sourceIdx is the hop the error was reported from. In order to be able
// to decrypt the error message, we need to know the source, which is
// why an error message can only be present if the source is known.
sourceIdx tlv.OptionalRecordT[tlv.TlvType0, uint8]
// msg is the error why a payment failed. If we identify the failure of
// a certain hop at the above index, but aren't able to decode the
// failure message we indicate this by not setting this field.
msg tlv.OptionalRecordT[tlv.TlvType1, failureMessage]
} }
// Record returns a TLV record that can be used to encode/decode a // Record returns a TLV record that can be used to encode/decode a
@@ -872,21 +891,35 @@ func (r *paymentFailure) Record() tlv.Record {
} }
return tlv.MakeDynamicRecord( return tlv.MakeDynamicRecord(
0, r, recordSize, encodePaymentFailure, decodePaymentFailure, 0, r, recordSize, encodePaymentFailure,
decodePaymentFailure,
) )
} }
func encodePaymentFailure(w io.Writer, val interface{}, _ *[8]byte) error { func encodePaymentFailure(w io.Writer, val interface{}, _ *[8]byte) error {
if v, ok := val.(*paymentFailure); ok { if v, ok := val.(*paymentFailure); ok {
var recordProducers []tlv.RecordProducer var recordProducers []tlv.RecordProducer
v.info.WhenSome(
func(r tlv.RecordT[tlv.TlvType0, paymentFailureInfo]) { v.sourceIdx.WhenSome(
recordProducers = append(recordProducers, &r) func(r tlv.RecordT[tlv.TlvType0, uint8]) {
recordProducers = append(
recordProducers, &r,
)
},
)
v.msg.WhenSome(
func(r tlv.RecordT[tlv.TlvType1, failureMessage]) {
recordProducers = append(
recordProducers, &r,
)
}, },
) )
return lnwire.EncodeRecordsTo( return lnwire.EncodeRecordsTo(
w, lnwire.ProduceRecordsSorted(recordProducers...), w, lnwire.ProduceRecordsSorted(
recordProducers...,
),
) )
} }
@@ -899,85 +932,32 @@ func decodePaymentFailure(r io.Reader, val interface{}, _ *[8]byte,
if v, ok := val.(*paymentFailure); ok { if v, ok := val.(*paymentFailure); ok {
var h paymentFailure var h paymentFailure
info := tlv.ZeroRecordT[tlv.TlvType0, paymentFailureInfo]() sourceIdx := tlv.ZeroRecordT[tlv.TlvType0, uint8]()
msg := tlv.ZeroRecordT[tlv.TlvType1, failureMessage]()
typeMap, err := lnwire.DecodeRecords( typeMap, err := lnwire.DecodeRecords(
r, lnwire.ProduceRecordsSorted(&info)...,
)
if err != nil {
return err
}
if _, ok := typeMap[h.info.TlvType()]; ok {
h.info = tlv.SomeRecordT(info)
}
*v = h
return nil
}
return tlv.NewTypeForDecodingErr(val, "routing.paymentFailure", l, l)
}
// paymentFailureInfo holds additional information about a payment failure.
type paymentFailureInfo struct {
sourceIdx tlv.RecordT[tlv.TlvType0, uint8]
msg tlv.RecordT[tlv.TlvType1, failureMessage]
}
// Record returns a TLV record that can be used to encode/decode a
// paymentFailureInfo to/from a TLV stream.
func (r *paymentFailureInfo) Record() tlv.Record {
recordSize := func() uint64 {
var (
b bytes.Buffer
buf [8]byte
)
if err := encodePaymentFailureInfo(&b, r, &buf); err != nil {
panic(err)
}
return uint64(len(b.Bytes()))
}
return tlv.MakeDynamicRecord(
0, r, recordSize, encodePaymentFailureInfo,
decodePaymentFailureInfo,
)
}
func encodePaymentFailureInfo(w io.Writer, val interface{}, _ *[8]byte) error {
if v, ok := val.(*paymentFailureInfo); ok {
return lnwire.EncodeRecordsTo(
w, lnwire.ProduceRecordsSorted(
&v.sourceIdx, &v.msg,
),
)
}
return tlv.NewTypeForEncodingErr(val, "routing.paymentFailureInfo")
}
func decodePaymentFailureInfo(r io.Reader, val interface{}, _ *[8]byte,
l uint64) error {
if v, ok := val.(*paymentFailureInfo); ok {
var h paymentFailureInfo
_, err := lnwire.DecodeRecords(
r, r,
lnwire.ProduceRecordsSorted(&h.sourceIdx, &h.msg)..., lnwire.ProduceRecordsSorted(&sourceIdx, &msg)...,
) )
if err != nil { if err != nil {
return err return err
} }
if _, ok := typeMap[h.sourceIdx.TlvType()]; ok {
h.sourceIdx = tlv.SomeRecordT(sourceIdx)
}
if _, ok := typeMap[h.msg.TlvType()]; ok {
h.msg = tlv.SomeRecordT(msg)
}
*v = h *v = h
return nil return nil
} }
return tlv.NewTypeForDecodingErr( return tlv.NewTypeForDecodingErr(
val, "routing.paymentFailureInfo", l, l, val, "routing.paymentFailure", l, l,
) )
} }
+15 -11
View File
@@ -7,6 +7,7 @@ import (
"time" "time"
"github.com/btcsuite/btcwallet/walletdb" "github.com/btcsuite/btcwallet/walletdb"
"github.com/lightningnetwork/lnd/fn/v2"
"github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
@@ -85,19 +86,19 @@ func TestMissionControlStore(t *testing.T) {
result1 := newPaymentResult( result1 := newPaymentResult(
99, mcStoreTestRoute, testTime, testTime, 99, mcStoreTestRoute, testTime, testTime,
newPaymentFailure( fn.Some(newPaymentFailure(
&failureSourceIdx, &failureSourceIdx,
lnwire.NewFailIncorrectDetails(100, 1000), lnwire.NewFailIncorrectDetails(100, 1000),
), )),
) )
result2 := newPaymentResult( result2 := newPaymentResult(
2, mcStoreTestRoute, testTime.Add(time.Hour), 2, mcStoreTestRoute, testTime.Add(time.Hour),
testTime.Add(time.Hour), testTime.Add(time.Hour),
newPaymentFailure( fn.Some(newPaymentFailure(
&failureSourceIdx, &failureSourceIdx,
lnwire.NewFailIncorrectDetails(100, 1000), lnwire.NewFailIncorrectDetails(100, 1000),
), )),
) )
// Store result. // Store result.
@@ -134,7 +135,7 @@ func TestMissionControlStore(t *testing.T) {
) )
result3.id = 3 result3.id = 3
result3.failure = tlv.SomeRecordT( result3.failure = tlv.SomeRecordT(
tlv.NewRecordT[tlv.TlvType3](*newPaymentFailure( tlv.NewRecordT[tlv.TlvType3](newPaymentFailure(
&failureSourceIdx, &lnwire.FailMPPTimeout{}, &failureSourceIdx, &lnwire.FailMPPTimeout{},
)), )),
) )
@@ -153,7 +154,7 @@ func TestMissionControlStore(t *testing.T) {
// Also demonstrate the persistence of a success result. // Also demonstrate the persistence of a success result.
result4 := newPaymentResult( result4 := newPaymentResult(
5, mcStoreTestRoute, testTime.Add(3*time.Hour), 5, mcStoreTestRoute, testTime.Add(3*time.Hour),
testTime.Add(3*time.Hour), nil, testTime.Add(3*time.Hour), fn.None[paymentFailure](),
) )
store.AddResult(result4) store.AddResult(result4)
require.NoError(t, store.storeResults()) require.NoError(t, store.storeResults())
@@ -186,7 +187,10 @@ func TestMissionControlStoreFlushing(t *testing.T) {
return newPaymentResult( return newPaymentResult(
lastID, mcStoreTestRoute, testTime.Add(-time.Hour), lastID, mcStoreTestRoute, testTime.Add(-time.Hour),
testTime, testTime,
newPaymentFailure(&failureSourceIdx, failureDetails), fn.Some(newPaymentFailure(
&failureSourceIdx,
failureDetails,
)),
) )
} }
@@ -287,10 +291,10 @@ func BenchmarkMissionControlStoreFlushing(b *testing.B) {
result := newPaymentResult( result := newPaymentResult(
lastID, mcStoreTestRoute, testTimeFwd, lastID, mcStoreTestRoute, testTimeFwd,
testTime, testTime,
newPaymentFailure( fn.Some(newPaymentFailure(
&failureSourceIdx, &failureSourceIdx,
failureDetails, failureDetails,
), )),
) )
store.AddResult(result) store.AddResult(result)
} }
@@ -305,10 +309,10 @@ func BenchmarkMissionControlStoreFlushing(b *testing.B) {
results[i] = newPaymentResult( results[i] = newPaymentResult(
0, mcStoreTestRoute, testTimeFwd, 0, mcStoreTestRoute, testTimeFwd,
testTime, testTime,
newPaymentFailure( fn.Some(newPaymentFailure(
&failureSourceIdx, &failureSourceIdx,
failureDetails, failureDetails,
), )),
) )
} }
+14 -5
View File
@@ -126,7 +126,9 @@ func (i *interpretedResult) processSuccess(route *mcRoute) {
// processFail processes a failed payment attempt. // processFail processes a failed payment attempt.
func (i *interpretedResult) processFail(rt *mcRoute, failure paymentFailure) { func (i *interpretedResult) processFail(rt *mcRoute, failure paymentFailure) {
if failure.info.IsNone() { // Not having a source index means that we were unable to decrypt the
// error message.
if failure.sourceIdx.IsNone() {
i.processPaymentOutcomeUnknown(rt) i.processPaymentOutcomeUnknown(rt)
return return
} }
@@ -136,10 +138,17 @@ func (i *interpretedResult) processFail(rt *mcRoute, failure paymentFailure) {
failMsg lnwire.FailureMessage failMsg lnwire.FailureMessage
) )
failure.info.WhenSome( failure.sourceIdx.WhenSome(
func(r tlv.RecordT[tlv.TlvType0, paymentFailureInfo]) { func(r tlv.RecordT[tlv.TlvType0, uint8]) {
idx = int(r.Val.sourceIdx.Val) idx = int(r.Val)
failMsg = r.Val.msg.Val.FailureMessage
failure.msg.WhenSome(
func(r tlv.RecordT[tlv.TlvType1,
failureMessage]) {
failMsg = r.Val.FailureMessage
},
)
}, },
) )
+1 -1
View File
@@ -732,7 +732,7 @@ func TestResultInterpretation(t *testing.T) {
t.Run(testCase.name, func(t *testing.T) { t.Run(testCase.name, func(t *testing.T) {
var failure fn.Option[paymentFailure] var failure fn.Option[paymentFailure]
if !testCase.success { if !testCase.success {
failure = fn.Some(*newPaymentFailure( failure = fn.Some(newPaymentFailure(
&testCase.failureSrcIdx, &testCase.failureSrcIdx,
testCase.failure, testCase.failure,
)) ))