mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-08-27 14:11:04 +02:00
routing+migration32: update MC encoding to use pure TLV
In this commit, we update an existing migration which at the time of writing has not been included in a release. We update it so that it converts the format used for MissionControl result encoding to use pure TLV instead. The 3 structs that have been updated are: `mcHop`, `mcRoute` and `paymentResult`.
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
package routing
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -16,6 +18,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/lightningnetwork/lnd/tlv"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -261,12 +264,39 @@ type MissionControlPairSnapshot struct {
|
||||
// paymentResult is the information that becomes available when a payment
|
||||
// attempt completes.
|
||||
type paymentResult struct {
|
||||
id uint64
|
||||
timeFwd, timeReply time.Time
|
||||
route *mcRoute
|
||||
success bool
|
||||
failureSourceIdx *int
|
||||
failure lnwire.FailureMessage
|
||||
id uint64
|
||||
timeFwd tlv.RecordT[tlv.TlvType0, uint64]
|
||||
timeReply tlv.RecordT[tlv.TlvType1, uint64]
|
||||
route tlv.RecordT[tlv.TlvType2, mcRoute]
|
||||
|
||||
// failure holds information related to the failure of a payment. The
|
||||
// presence of this record indicates a payment failure. The absence of
|
||||
// this record indicates a successful payment.
|
||||
failure tlv.OptionalRecordT[tlv.TlvType3, paymentFailure]
|
||||
}
|
||||
|
||||
// newPaymentResult constructs a new paymentResult.
|
||||
func newPaymentResult(id uint64, rt *mcRoute, timeFwd, timeReply time.Time,
|
||||
failure *paymentFailure) *paymentResult {
|
||||
|
||||
result := &paymentResult{
|
||||
id: id,
|
||||
timeFwd: tlv.NewPrimitiveRecord[tlv.TlvType0](
|
||||
uint64(timeFwd.UnixNano()),
|
||||
),
|
||||
timeReply: tlv.NewPrimitiveRecord[tlv.TlvType1](
|
||||
uint64(timeReply.UnixNano()),
|
||||
),
|
||||
route: tlv.NewRecordT[tlv.TlvType2](*rt),
|
||||
}
|
||||
|
||||
if failure != nil {
|
||||
result.failure = tlv.SomeRecordT(
|
||||
tlv.NewRecordT[tlv.TlvType3](*failure),
|
||||
)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// NewMissionController returns a new instance of MissionController.
|
||||
@@ -590,15 +620,10 @@ func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route,
|
||||
|
||||
timestamp := m.cfg.clock.Now()
|
||||
|
||||
result := &paymentResult{
|
||||
success: false,
|
||||
timeFwd: timestamp,
|
||||
timeReply: timestamp,
|
||||
id: paymentID,
|
||||
failureSourceIdx: failureSourceIdx,
|
||||
failure: failure,
|
||||
route: extractMCRoute(rt),
|
||||
}
|
||||
result := newPaymentResult(
|
||||
paymentID, extractMCRoute(rt), timestamp, timestamp,
|
||||
newPaymentFailure(failureSourceIdx, failure),
|
||||
)
|
||||
|
||||
return m.processPaymentResult(result)
|
||||
}
|
||||
@@ -610,15 +635,12 @@ func (m *MissionControl) ReportPaymentSuccess(paymentID uint64,
|
||||
|
||||
timestamp := m.cfg.clock.Now()
|
||||
|
||||
result := &paymentResult{
|
||||
timeFwd: timestamp,
|
||||
timeReply: timestamp,
|
||||
id: paymentID,
|
||||
success: true,
|
||||
route: extractMCRoute(rt),
|
||||
}
|
||||
result := newPaymentResult(
|
||||
paymentID, extractMCRoute(rt), timestamp, timestamp, nil,
|
||||
)
|
||||
|
||||
_, err := m.processPaymentResult(result)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -646,14 +668,11 @@ func (m *MissionControl) applyPaymentResult(
|
||||
result *paymentResult) *channeldb.FailureReason {
|
||||
|
||||
// Interpret result.
|
||||
i := interpretResult(
|
||||
result.route, result.success, result.failureSourceIdx,
|
||||
result.failure,
|
||||
)
|
||||
i := interpretResult(&result.route.Val, result.failure.ValOpt())
|
||||
|
||||
if i.policyFailure != nil {
|
||||
if m.state.requestSecondChance(
|
||||
result.timeReply,
|
||||
time.Unix(0, int64(result.timeReply.Val)),
|
||||
i.policyFailure.From, i.policyFailure.To,
|
||||
) {
|
||||
return nil
|
||||
@@ -681,7 +700,10 @@ func (m *MissionControl) applyPaymentResult(
|
||||
m.log.Debugf("Reporting node failure to Mission Control: "+
|
||||
"node=%v", *i.nodeFailure)
|
||||
|
||||
m.state.setAllFail(*i.nodeFailure, result.timeReply)
|
||||
m.state.setAllFail(
|
||||
*i.nodeFailure,
|
||||
time.Unix(0, int64(result.timeReply.Val)),
|
||||
)
|
||||
}
|
||||
|
||||
for pair, pairResult := range i.pairResults {
|
||||
@@ -698,7 +720,9 @@ func (m *MissionControl) applyPaymentResult(
|
||||
}
|
||||
|
||||
m.state.setLastPairResult(
|
||||
pair.From, pair.To, result.timeReply, &pairResult, false,
|
||||
pair.From, pair.To,
|
||||
time.Unix(0, int64(result.timeReply.Val)), &pairResult,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -803,3 +827,158 @@ func (n *namespacedDB) purge() error {
|
||||
return err
|
||||
}, 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
|
||||
// index is nil, then an empty paymentFailure is returned. This represents a
|
||||
// failure with unknown details. Otherwise, the index and failure message are
|
||||
// used to populate the info field of the paymentFailure.
|
||||
func newPaymentFailure(sourceIdx *int,
|
||||
failureMsg lnwire.FailureMessage) *paymentFailure {
|
||||
|
||||
if sourceIdx == nil {
|
||||
return &paymentFailure{}
|
||||
}
|
||||
|
||||
info := paymentFailureInfo{
|
||||
sourceIdx: tlv.NewPrimitiveRecord[tlv.TlvType0](
|
||||
uint8(*sourceIdx),
|
||||
),
|
||||
msg: tlv.NewRecordT[tlv.TlvType1](failureMessage{failureMsg}),
|
||||
}
|
||||
|
||||
return &paymentFailure{
|
||||
info: tlv.SomeRecordT(tlv.NewRecordT[tlv.TlvType0](info)),
|
||||
}
|
||||
}
|
||||
|
||||
// Record returns a TLV record that can be used to encode/decode a
|
||||
// paymentFailure to/from a TLV stream.
|
||||
func (r *paymentFailure) Record() tlv.Record {
|
||||
recordSize := func() uint64 {
|
||||
var (
|
||||
b bytes.Buffer
|
||||
buf [8]byte
|
||||
)
|
||||
if err := encodePaymentFailure(&b, r, &buf); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return uint64(len(b.Bytes()))
|
||||
}
|
||||
|
||||
return tlv.MakeDynamicRecord(
|
||||
0, r, recordSize, encodePaymentFailure, decodePaymentFailure,
|
||||
)
|
||||
}
|
||||
|
||||
func encodePaymentFailure(w io.Writer, val interface{}, _ *[8]byte) error {
|
||||
if v, ok := val.(*paymentFailure); ok {
|
||||
var recordProducers []tlv.RecordProducer
|
||||
v.info.WhenSome(
|
||||
func(r tlv.RecordT[tlv.TlvType0, paymentFailureInfo]) {
|
||||
recordProducers = append(recordProducers, &r)
|
||||
},
|
||||
)
|
||||
|
||||
return lnwire.EncodeRecordsTo(
|
||||
w, lnwire.ProduceRecordsSorted(recordProducers...),
|
||||
)
|
||||
}
|
||||
|
||||
return tlv.NewTypeForEncodingErr(val, "routing.paymentFailure")
|
||||
}
|
||||
|
||||
func decodePaymentFailure(r io.Reader, val interface{}, _ *[8]byte,
|
||||
l uint64) error {
|
||||
|
||||
if v, ok := val.(*paymentFailure); ok {
|
||||
var h paymentFailure
|
||||
|
||||
info := tlv.ZeroRecordT[tlv.TlvType0, paymentFailureInfo]()
|
||||
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,
|
||||
lnwire.ProduceRecordsSorted(&h.sourceIdx, &h.msg)...,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = h
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return tlv.NewTypeForDecodingErr(
|
||||
val, "routing.paymentFailureInfo", l, l,
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user