routing/pathfind: set single-shot MPP if payment addr is known
This commit is contained in:
parent
7965cb08db
commit
0993256b77
@ -99,11 +99,12 @@ type edgePolicyWithSource struct {
|
|||||||
// finalHopParams encapsulates various parameters for route construction that
|
// finalHopParams encapsulates various parameters for route construction that
|
||||||
// apply to the final hop in a route. These features include basic payment data
|
// apply to the final hop in a route. These features include basic payment data
|
||||||
// such as amounts and cltvs, as well as more complex features like destination
|
// such as amounts and cltvs, as well as more complex features like destination
|
||||||
// custom records.
|
// custom records and payment address.
|
||||||
type finalHopParams struct {
|
type finalHopParams struct {
|
||||||
amt lnwire.MilliSatoshi
|
amt lnwire.MilliSatoshi
|
||||||
cltvDelta uint16
|
cltvDelta uint16
|
||||||
records record.CustomSet
|
records record.CustomSet
|
||||||
|
paymentAddr *[32]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// newRoute constructs a route using the provided path and final hop constraints.
|
// newRoute constructs a route using the provided path and final hop constraints.
|
||||||
@ -152,6 +153,7 @@ func newRoute(sourceVertex route.Vertex,
|
|||||||
outgoingTimeLock uint32
|
outgoingTimeLock uint32
|
||||||
tlvPayload bool
|
tlvPayload bool
|
||||||
customRecords record.CustomSet
|
customRecords record.CustomSet
|
||||||
|
mpp *record.MPP
|
||||||
)
|
)
|
||||||
|
|
||||||
// Define a helper function that checks this edge's feature
|
// Define a helper function that checks this edge's feature
|
||||||
@ -191,6 +193,21 @@ func newRoute(sourceVertex route.Vertex,
|
|||||||
"custom records")
|
"custom records")
|
||||||
}
|
}
|
||||||
customRecords = finalHop.records
|
customRecords = finalHop.records
|
||||||
|
|
||||||
|
// If we're attaching a payment addr but the receiver
|
||||||
|
// doesn't support both TLV and payment addrs, fail.
|
||||||
|
payAddr := supports(lnwire.PaymentAddrOptional)
|
||||||
|
if !payAddr && finalHop.paymentAddr != nil {
|
||||||
|
return nil, errors.New("cannot attach " +
|
||||||
|
"payment addr")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise attach the mpp record if it exists.
|
||||||
|
if finalHop.paymentAddr != nil {
|
||||||
|
mpp = record.NewMPP(
|
||||||
|
finalHop.amt, *finalHop.paymentAddr,
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// The amount that the current hop needs to forward is
|
// The amount that the current hop needs to forward is
|
||||||
// equal to the incoming amount of the next hop.
|
// equal to the incoming amount of the next hop.
|
||||||
@ -220,6 +237,7 @@ func newRoute(sourceVertex route.Vertex,
|
|||||||
OutgoingTimeLock: outgoingTimeLock,
|
OutgoingTimeLock: outgoingTimeLock,
|
||||||
LegacyPayload: !tlvPayload,
|
LegacyPayload: !tlvPayload,
|
||||||
CustomRecords: customRecords,
|
CustomRecords: customRecords,
|
||||||
|
MPP: mpp,
|
||||||
}
|
}
|
||||||
|
|
||||||
hops = append([]*route.Hop{currentHop}, hops...)
|
hops = append([]*route.Hop{currentHop}, hops...)
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -1061,6 +1062,8 @@ func TestNewRoute(t *testing.T) {
|
|||||||
var sourceKey [33]byte
|
var sourceKey [33]byte
|
||||||
sourceVertex := route.Vertex(sourceKey)
|
sourceVertex := route.Vertex(sourceKey)
|
||||||
|
|
||||||
|
testPaymentAddr := [32]byte{0x01, 0x02, 0x03}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
startingHeight = 100
|
startingHeight = 100
|
||||||
finalHopCLTV = 1
|
finalHopCLTV = 1
|
||||||
@ -1099,6 +1102,8 @@ func TestNewRoute(t *testing.T) {
|
|||||||
// overwrite the final hop's feature vector in the graph.
|
// overwrite the final hop's feature vector in the graph.
|
||||||
destFeatures *lnwire.FeatureVector
|
destFeatures *lnwire.FeatureVector
|
||||||
|
|
||||||
|
paymentAddr *[32]byte
|
||||||
|
|
||||||
// expectedFees is a list of fees that every hop is expected
|
// expectedFees is a list of fees that every hop is expected
|
||||||
// to charge for forwarding.
|
// to charge for forwarding.
|
||||||
expectedFees []lnwire.MilliSatoshi
|
expectedFees []lnwire.MilliSatoshi
|
||||||
@ -1129,6 +1134,8 @@ func TestNewRoute(t *testing.T) {
|
|||||||
expectedErrorCode errorCode
|
expectedErrorCode errorCode
|
||||||
|
|
||||||
expectedTLVPayload bool
|
expectedTLVPayload bool
|
||||||
|
|
||||||
|
expectedMPP *record.MPP
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
// For a single hop payment, no fees are expected to be paid.
|
// For a single hop payment, no fees are expected to be paid.
|
||||||
@ -1171,6 +1178,26 @@ func TestNewRoute(t *testing.T) {
|
|||||||
expectedTotalAmount: 100130,
|
expectedTotalAmount: 100130,
|
||||||
expectedTotalTimeLock: 6,
|
expectedTotalTimeLock: 6,
|
||||||
expectedTLVPayload: true,
|
expectedTLVPayload: true,
|
||||||
|
}, {
|
||||||
|
// For a two hop payment, only the fee for the first hop
|
||||||
|
// needs to be paid. The destination hop does not require
|
||||||
|
// a fee to receive the payment.
|
||||||
|
name: "two hop single shot mpp",
|
||||||
|
destFeatures: tlvPayAddrFeatures,
|
||||||
|
paymentAddr: &testPaymentAddr,
|
||||||
|
paymentAmount: 100000,
|
||||||
|
hops: []*channeldb.ChannelEdgePolicy{
|
||||||
|
createHop(0, 1000, 1000000, 10),
|
||||||
|
createHop(30, 1000, 1000000, 5),
|
||||||
|
},
|
||||||
|
expectedFees: []lnwire.MilliSatoshi{130, 0},
|
||||||
|
expectedTimeLocks: []uint32{1, 1},
|
||||||
|
expectedTotalAmount: 100130,
|
||||||
|
expectedTotalTimeLock: 6,
|
||||||
|
expectedTLVPayload: true,
|
||||||
|
expectedMPP: record.NewMPP(
|
||||||
|
100000, testPaymentAddr,
|
||||||
|
),
|
||||||
}, {
|
}, {
|
||||||
// A three hop payment where the first and second hop
|
// A three hop payment where the first and second hop
|
||||||
// will both charge 1 msat. The fee for the first hop
|
// will both charge 1 msat. The fee for the first hop
|
||||||
@ -1284,20 +1311,29 @@ func TestNewRoute(t *testing.T) {
|
|||||||
if !finalHop.LegacyPayload !=
|
if !finalHop.LegacyPayload !=
|
||||||
testCase.expectedTLVPayload {
|
testCase.expectedTLVPayload {
|
||||||
|
|
||||||
t.Errorf("Expected tlv payload: %t, "+
|
t.Errorf("Expected final hop tlv payload: %t, "+
|
||||||
"but got: %t instead",
|
"but got: %t instead",
|
||||||
testCase.expectedTLVPayload,
|
testCase.expectedTLVPayload,
|
||||||
!finalHop.LegacyPayload)
|
!finalHop.LegacyPayload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(
|
||||||
|
finalHop.MPP, testCase.expectedMPP,
|
||||||
|
) {
|
||||||
|
t.Errorf("Expected final hop mpp field: %v, "+
|
||||||
|
" but got: %v instead",
|
||||||
|
testCase.expectedMPP, finalHop.MPP)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
route, err := newRoute(
|
route, err := newRoute(
|
||||||
sourceVertex, testCase.hops, startingHeight,
|
sourceVertex, testCase.hops, startingHeight,
|
||||||
finalHopParams{
|
finalHopParams{
|
||||||
amt: testCase.paymentAmount,
|
amt: testCase.paymentAmount,
|
||||||
cltvDelta: finalHopCLTV,
|
cltvDelta: finalHopCLTV,
|
||||||
records: nil,
|
records: nil,
|
||||||
|
paymentAddr: testCase.paymentAddr,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user