mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-06-23 15:22:38 +02:00
lnrpc+routing: convert amt pointer to fn.Option
This commit is contained in:
parent
8b32e3e785
commit
452db01ad7
@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
|
"github.com/lightningnetwork/lnd/fn"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
@ -1411,10 +1412,10 @@ func (s *Server) BuildRoute(_ context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prepare BuildRoute call parameters from rpc request.
|
// Prepare BuildRoute call parameters from rpc request.
|
||||||
var amt *lnwire.MilliSatoshi
|
var amt fn.Option[lnwire.MilliSatoshi]
|
||||||
if req.AmtMsat != 0 {
|
if req.AmtMsat != 0 {
|
||||||
rpcAmt := lnwire.MilliSatoshi(req.AmtMsat)
|
rpcAmt := lnwire.MilliSatoshi(req.AmtMsat)
|
||||||
amt = &rpcAmt
|
amt = fn.Some(rpcAmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
var outgoingChan *uint64
|
var outgoingChan *uint64
|
||||||
|
@ -1406,7 +1406,7 @@ func (e ErrNoChannel) Error() string {
|
|||||||
// BuildRoute returns a fully specified route based on a list of pubkeys. If
|
// BuildRoute returns a fully specified route based on a list of pubkeys. If
|
||||||
// amount is nil, the minimum routable amount is used. To force a specific
|
// amount is nil, the minimum routable amount is used. To force a specific
|
||||||
// outgoing channel, use the outgoingChan parameter.
|
// outgoing channel, use the outgoingChan parameter.
|
||||||
func (r *ChannelRouter) BuildRoute(amt *lnwire.MilliSatoshi,
|
func (r *ChannelRouter) BuildRoute(amt fn.Option[lnwire.MilliSatoshi],
|
||||||
hops []route.Vertex, outgoingChan *uint64,
|
hops []route.Vertex, outgoingChan *uint64,
|
||||||
finalCltvDelta int32, payAddr *[32]byte) (*route.Route, error) {
|
finalCltvDelta int32, payAddr *[32]byte) (*route.Route, error) {
|
||||||
|
|
||||||
@ -1439,43 +1439,36 @@ func (r *ChannelRouter) BuildRoute(amt *lnwire.MilliSatoshi,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no amount is specified, we need to build a route for the minimum
|
|
||||||
// amount that this route can carry.
|
|
||||||
useMinAmt := amt == nil
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
receiverAmt lnwire.MilliSatoshi
|
receiverAmt lnwire.MilliSatoshi
|
||||||
|
senderAmt lnwire.MilliSatoshi
|
||||||
pathEdges []*unifiedEdge
|
pathEdges []*unifiedEdge
|
||||||
)
|
)
|
||||||
|
|
||||||
if useMinAmt {
|
// We determine the edges compatible with the requested amount, as well
|
||||||
// For minimum amount routes, aim to deliver at least 1 msat to
|
// as the amount to send, which can be used to determine the final
|
||||||
// the destination. There are nodes in the wild that have a
|
// receiver amount, if a minimal amount was requested.
|
||||||
// min_htlc channel policy of zero, which could lead to a zero
|
pathEdges, senderAmt, err = senderAmtBackwardPass(
|
||||||
// amount payment being made.
|
unifiers, amt, bandwidthHints,
|
||||||
var senderAmt lnwire.MilliSatoshi
|
)
|
||||||
pathEdges, senderAmt, err = senderAmtBackwardPass(
|
if err != nil {
|
||||||
unifiers, useMinAmt, 1, bandwidthHints,
|
return nil, err
|
||||||
)
|
}
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
receiverAmt, err = receiverAmtForwardPass(senderAmt, pathEdges)
|
// For the minimal amount search, we need to do a forward pass to find a
|
||||||
if err != nil {
|
// larger receiver amount due to possible min HTLC bumps, otherwise we
|
||||||
return nil, err
|
// just use the requested amount.
|
||||||
}
|
receiverAmt, err = fn.ElimOption(
|
||||||
} else {
|
amt,
|
||||||
// If an amount is specified, we need to build a route that
|
func() fn.Result[lnwire.MilliSatoshi] {
|
||||||
// delivers exactly this amount to the final destination.
|
return fn.NewResult(
|
||||||
pathEdges, _, err = senderAmtBackwardPass(
|
receiverAmtForwardPass(senderAmt, pathEdges),
|
||||||
unifiers, useMinAmt, *amt, bandwidthHints,
|
)
|
||||||
)
|
},
|
||||||
if err != nil {
|
fn.Ok[lnwire.MilliSatoshi],
|
||||||
return nil, err
|
).Unpack()
|
||||||
}
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
receiverAmt = *amt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the current block height outside the routing transaction, to
|
// Fetch the current block height outside the routing transaction, to
|
||||||
@ -1545,9 +1538,9 @@ func getEdgeUnifiers(source route.Vertex, hops []route.Vertex,
|
|||||||
|
|
||||||
// senderAmtBackwardPass returns a list of unified edges for the given route and
|
// senderAmtBackwardPass returns a list of unified edges for the given route and
|
||||||
// determines the amount that should be sent to fulfill min HTLC requirements.
|
// determines the amount that should be sent to fulfill min HTLC requirements.
|
||||||
// The minimal sender amount can be searched for by activating useMinAmt.
|
// The minimal sender amount can be searched for by using amt=None.
|
||||||
func senderAmtBackwardPass(unifiers []*edgeUnifier, useMinAmt bool,
|
func senderAmtBackwardPass(unifiers []*edgeUnifier,
|
||||||
receiverAmt lnwire.MilliSatoshi,
|
amt fn.Option[lnwire.MilliSatoshi],
|
||||||
bandwidthHints bandwidthHints) ([]*unifiedEdge, lnwire.MilliSatoshi,
|
bandwidthHints bandwidthHints) ([]*unifiedEdge, lnwire.MilliSatoshi,
|
||||||
error) {
|
error) {
|
||||||
|
|
||||||
@ -1563,11 +1556,15 @@ func senderAmtBackwardPass(unifiers []*edgeUnifier, useMinAmt bool,
|
|||||||
// incomingAmt tracks the amount that is forwarded on the edges of a
|
// incomingAmt tracks the amount that is forwarded on the edges of a
|
||||||
// route. The last hop only forwards the amount that the receiver should
|
// route. The last hop only forwards the amount that the receiver should
|
||||||
// receive, as there are no fees paid to the last node.
|
// receive, as there are no fees paid to the last node.
|
||||||
incomingAmt := receiverAmt
|
// For minimum amount routes, aim to deliver at least 1 msat to
|
||||||
|
// the destination. There are nodes in the wild that have a
|
||||||
|
// min_htlc channel policy of zero, which could lead to a zero
|
||||||
|
// amount payment being made.
|
||||||
|
incomingAmt := amt.UnwrapOr(1)
|
||||||
|
|
||||||
// If using min amt, increase the amount if needed to fulfill min HTLC
|
// If using min amt, increase the amount if needed to fulfill min HTLC
|
||||||
// requirements.
|
// requirements.
|
||||||
if useMinAmt {
|
if amt.IsNone() {
|
||||||
min := edgeUnifier.minAmt()
|
min := edgeUnifier.minAmt()
|
||||||
if min > incomingAmt {
|
if min > incomingAmt {
|
||||||
incomingAmt = min
|
incomingAmt = min
|
||||||
@ -1591,7 +1588,7 @@ func senderAmtBackwardPass(unifiers []*edgeUnifier, useMinAmt bool,
|
|||||||
|
|
||||||
// If using min amt, increase the amount if needed to fulfill
|
// If using min amt, increase the amount if needed to fulfill
|
||||||
// min HTLC requirements.
|
// min HTLC requirements.
|
||||||
if useMinAmt {
|
if amt.IsNone() {
|
||||||
min := edgeUnifier.minAmt()
|
min := edgeUnifier.minAmt()
|
||||||
if min > incomingAmt {
|
if min > incomingAmt {
|
||||||
incomingAmt = min
|
incomingAmt = min
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/channeldb/models"
|
"github.com/lightningnetwork/lnd/channeldb/models"
|
||||||
"github.com/lightningnetwork/lnd/clock"
|
"github.com/lightningnetwork/lnd/clock"
|
||||||
|
"github.com/lightningnetwork/lnd/fn"
|
||||||
"github.com/lightningnetwork/lnd/graph"
|
"github.com/lightningnetwork/lnd/graph"
|
||||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
@ -1641,14 +1642,16 @@ func TestBuildRoute(t *testing.T) {
|
|||||||
_, err = rand.Read(payAddr[:])
|
_, err = rand.Read(payAddr[:])
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
noAmt := fn.None[lnwire.MilliSatoshi]()
|
||||||
|
|
||||||
// Test that we can't build a route when no hops are given.
|
// Test that we can't build a route when no hops are given.
|
||||||
hops = []route.Vertex{}
|
hops = []route.Vertex{}
|
||||||
_, err = ctx.router.BuildRoute(nil, hops, nil, 40, nil)
|
_, err = ctx.router.BuildRoute(noAmt, hops, nil, 40, nil)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
// Create hop list for an unknown destination.
|
// Create hop list for an unknown destination.
|
||||||
hops := []route.Vertex{ctx.aliases["b"], ctx.aliases["y"]}
|
hops := []route.Vertex{ctx.aliases["b"], ctx.aliases["y"]}
|
||||||
_, err = ctx.router.BuildRoute(nil, hops, nil, 40, &payAddr)
|
_, err = ctx.router.BuildRoute(noAmt, hops, nil, 40, &payAddr)
|
||||||
noChanErr := ErrNoChannel{}
|
noChanErr := ErrNoChannel{}
|
||||||
require.ErrorAs(t, err, &noChanErr)
|
require.ErrorAs(t, err, &noChanErr)
|
||||||
require.Equal(t, 1, noChanErr.position)
|
require.Equal(t, 1, noChanErr.position)
|
||||||
@ -1658,7 +1661,7 @@ func TestBuildRoute(t *testing.T) {
|
|||||||
amt := lnwire.NewMSatFromSatoshis(100)
|
amt := lnwire.NewMSatFromSatoshis(100)
|
||||||
|
|
||||||
// Build the route for the given amount.
|
// Build the route for the given amount.
|
||||||
rt, err := ctx.router.BuildRoute(&amt, hops, nil, 40, &payAddr)
|
rt, err := ctx.router.BuildRoute(fn.Some(amt), hops, nil, 40, &payAddr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Check that we get the expected route back. The total amount should be
|
// Check that we get the expected route back. The total amount should be
|
||||||
@ -1668,7 +1671,7 @@ func TestBuildRoute(t *testing.T) {
|
|||||||
require.Equal(t, lnwire.MilliSatoshi(106000), rt.TotalAmount)
|
require.Equal(t, lnwire.MilliSatoshi(106000), rt.TotalAmount)
|
||||||
|
|
||||||
// Build the route for the minimum amount.
|
// Build the route for the minimum amount.
|
||||||
rt, err = ctx.router.BuildRoute(nil, hops, nil, 40, &payAddr)
|
rt, err = ctx.router.BuildRoute(noAmt, hops, nil, 40, &payAddr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Check that we get the expected route back. The minimum that we can
|
// Check that we get the expected route back. The minimum that we can
|
||||||
@ -1684,7 +1687,7 @@ func TestBuildRoute(t *testing.T) {
|
|||||||
// Test a route that contains incompatible channel htlc constraints.
|
// Test a route that contains incompatible channel htlc constraints.
|
||||||
// There is no amount that can pass through both channel 5 and 4.
|
// There is no amount that can pass through both channel 5 and 4.
|
||||||
hops = []route.Vertex{ctx.aliases["e"], ctx.aliases["c"]}
|
hops = []route.Vertex{ctx.aliases["e"], ctx.aliases["c"]}
|
||||||
_, err = ctx.router.BuildRoute(nil, hops, nil, 40, nil)
|
_, err = ctx.router.BuildRoute(noAmt, hops, nil, 40, nil)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
noChanErr = ErrNoChannel{}
|
noChanErr = ErrNoChannel{}
|
||||||
require.ErrorAs(t, err, &noChanErr)
|
require.ErrorAs(t, err, &noChanErr)
|
||||||
@ -1702,7 +1705,7 @@ func TestBuildRoute(t *testing.T) {
|
|||||||
// amount that could be delivered to the receiver of 21819 msat, using
|
// amount that could be delivered to the receiver of 21819 msat, using
|
||||||
// policy of channel 3.
|
// policy of channel 3.
|
||||||
hops = []route.Vertex{ctx.aliases["b"], ctx.aliases["z"]}
|
hops = []route.Vertex{ctx.aliases["b"], ctx.aliases["z"]}
|
||||||
rt, err = ctx.router.BuildRoute(nil, hops, nil, 40, &payAddr)
|
rt, err = ctx.router.BuildRoute(noAmt, hops, nil, 40, &payAddr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
checkHops(rt, []uint64{1, 8}, payAddr)
|
checkHops(rt, []uint64{1, 8}, payAddr)
|
||||||
require.Equal(t, lnwire.MilliSatoshi(21200), rt.TotalAmount)
|
require.Equal(t, lnwire.MilliSatoshi(21200), rt.TotalAmount)
|
||||||
@ -1714,7 +1717,7 @@ func TestBuildRoute(t *testing.T) {
|
|||||||
// We get 106000 - 1000 (base in) - 0.001 * 106000 (rate in) = 104894.
|
// We get 106000 - 1000 (base in) - 0.001 * 106000 (rate in) = 104894.
|
||||||
hops = []route.Vertex{ctx.aliases["d"], ctx.aliases["f"]}
|
hops = []route.Vertex{ctx.aliases["d"], ctx.aliases["f"]}
|
||||||
amt = lnwire.NewMSatFromSatoshis(100)
|
amt = lnwire.NewMSatFromSatoshis(100)
|
||||||
rt, err = ctx.router.BuildRoute(&amt, hops, nil, 40, &payAddr)
|
rt, err = ctx.router.BuildRoute(fn.Some(amt), hops, nil, 40, &payAddr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
checkHops(rt, []uint64{9, 10}, payAddr)
|
checkHops(rt, []uint64{9, 10}, payAddr)
|
||||||
require.EqualValues(t, 104894, rt.TotalAmount)
|
require.EqualValues(t, 104894, rt.TotalAmount)
|
||||||
@ -1728,7 +1731,7 @@ func TestBuildRoute(t *testing.T) {
|
|||||||
// of 20179 msat, which results in underpayment of 1 msat in fee. There
|
// of 20179 msat, which results in underpayment of 1 msat in fee. There
|
||||||
// is a third pass through newRoute in which this gets corrected to end
|
// is a third pass through newRoute in which this gets corrected to end
|
||||||
hops = []route.Vertex{ctx.aliases["d"], ctx.aliases["f"]}
|
hops = []route.Vertex{ctx.aliases["d"], ctx.aliases["f"]}
|
||||||
rt, err = ctx.router.BuildRoute(nil, hops, nil, 40, &payAddr)
|
rt, err = ctx.router.BuildRoute(noAmt, hops, nil, 40, &payAddr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
checkHops(rt, []uint64{9, 10}, payAddr)
|
checkHops(rt, []uint64{9, 10}, payAddr)
|
||||||
require.EqualValues(t, 20180, rt.TotalAmount, "%v", rt.TotalAmount)
|
require.EqualValues(t, 20180, rt.TotalAmount, "%v", rt.TotalAmount)
|
||||||
@ -1919,20 +1922,20 @@ func TestSenderAmtBackwardPass(t *testing.T) {
|
|||||||
// A search for an amount that is below the minimum HTLC amount should
|
// A search for an amount that is below the minimum HTLC amount should
|
||||||
// fail.
|
// fail.
|
||||||
_, _, err := senderAmtBackwardPass(
|
_, _, err := senderAmtBackwardPass(
|
||||||
edgeUnifiers, false, minHTLC-1, &bandwidthHints,
|
edgeUnifiers, fn.Some(minHTLC-1), &bandwidthHints,
|
||||||
)
|
)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
// Do a min amount search.
|
// Do a min amount search.
|
||||||
unifiedEdges, senderAmount, err := senderAmtBackwardPass(
|
_, senderAmount, err := senderAmtBackwardPass(
|
||||||
edgeUnifiers, true, 1, &bandwidthHints,
|
edgeUnifiers, fn.None[lnwire.MilliSatoshi](), &bandwidthHints,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, minHTLC+333+222+222+111, senderAmount)
|
require.Equal(t, minHTLC+333+222+222+111, senderAmount)
|
||||||
|
|
||||||
// Do a search for a specific amount.
|
// Do a search for a specific amount.
|
||||||
unifiedEdges, senderAmount, err = senderAmtBackwardPass(
|
unifiedEdges, senderAmount, err := senderAmtBackwardPass(
|
||||||
edgeUnifiers, false, testReceiverAmt, &bandwidthHints,
|
edgeUnifiers, fn.Some(testReceiverAmt), &bandwidthHints,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, testReceiverAmt+333+222+222+111, senderAmount)
|
require.Equal(t, testReceiverAmt+333+222+222+111, senderAmount)
|
||||||
@ -1961,7 +1964,7 @@ func TestSenderAmtBackwardPass(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unifiedEdges, senderAmount, err = senderAmtBackwardPass(
|
unifiedEdges, senderAmount, err = senderAmtBackwardPass(
|
||||||
edgeUnifiers, false, testReceiverAmt, &bandwidthHints,
|
edgeUnifiers, fn.Some(testReceiverAmt), &bandwidthHints,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user