multi: add node omission list for blinded paths
This commit is contained in:
10 files changed
+1252
-1140
No files matched your search
@@ -110,6 +110,12 @@ var addInvoiceCommand = cli.Command{
|
|||||||
"to an invoice. This option will only be " +
|
"to an invoice. This option will only be " +
|
||||||
"used if `--blind` has also been set.",
|
"used if `--blind` has also been set.",
|
||||||
},
|
},
|
||||||
|
cli.StringSliceFlag{
|
||||||
|
Name: "blinded_path_omit_node",
|
||||||
|
Usage: "The pub key (in hex) of a node not to " +
|
||||||
|
"use on a blinded path. The flag may be " +
|
||||||
|
"specified multiple times.",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: actionDecorator(addInvoice),
|
Action: actionDecorator(addInvoice),
|
||||||
}
|
}
|
||||||
@@ -221,6 +227,17 @@ func parseBlindedPathCfg(ctx *cli.Context) (*lnrpc.BlindedPathConfig, error) {
|
|||||||
blindCfg.MaxNumPaths = &maxPaths
|
blindCfg.MaxNumPaths = &maxPaths
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, pubKey := range ctx.StringSlice("blinded_path_omit_node") {
|
||||||
|
pubKeyBytes, err := hex.DecodeString(pubKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
blindCfg.NodeOmissionList = append(
|
||||||
|
blindCfg.NodeOmissionList, pubKeyBytes,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return &blindCfg, nil
|
return &blindCfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -412,6 +412,14 @@
|
|||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int64",
|
"format": "int64",
|
||||||
"description": "The maximum number of blinded paths to select and add to an invoice."
|
"description": "The maximum number of blinded paths to select and add to an invoice."
|
||||||
|
},
|
||||||
|
"node_omission_list": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "byte"
|
||||||
|
},
|
||||||
|
"description": "A list of node IDs of nodes that should not be used in any of our generated\nblinded paths."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
+1152
-1139
File diff suppressed because it is too large.
Load diff
@@ -3867,6 +3867,12 @@ message BlindedPathConfig {
|
|||||||
The maximum number of blinded paths to select and add to an invoice.
|
The maximum number of blinded paths to select and add to an invoice.
|
||||||
*/
|
*/
|
||||||
optional uint32 max_num_paths = 3;
|
optional uint32 max_num_paths = 3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
A list of node IDs of nodes that should not be used in any of our generated
|
||||||
|
blinded paths.
|
||||||
|
*/
|
||||||
|
repeated bytes node_omission_list = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum InvoiceHTLCState {
|
enum InvoiceHTLCState {
|
||||||
|
|||||||
@@ -3561,6 +3561,14 @@
|
|||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int64",
|
"format": "int64",
|
||||||
"description": "The maximum number of blinded paths to select and add to an invoice."
|
"description": "The maximum number of blinded paths to select and add to an invoice."
|
||||||
|
},
|
||||||
|
"node_omission_list": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "byte"
|
||||||
|
},
|
||||||
|
"description": "A list of node IDs of nodes that should not be used in any of our generated\nblinded paths."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,6 +14,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/feature"
|
"github.com/lightningnetwork/lnd/feature"
|
||||||
|
"github.com/lightningnetwork/lnd/fn"
|
||||||
"github.com/lightningnetwork/lnd/lnutils"
|
"github.com/lightningnetwork/lnd/lnutils"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/record"
|
"github.com/lightningnetwork/lnd/record"
|
||||||
@@ -1150,6 +1151,10 @@ type blindedPathRestrictions struct {
|
|||||||
// path. This doesn't include our node, so if the maximum is 1, then
|
// path. This doesn't include our node, so if the maximum is 1, then
|
||||||
// the path will contain our node along with an introduction node hop.
|
// the path will contain our node along with an introduction node hop.
|
||||||
maxNumHops uint8
|
maxNumHops uint8
|
||||||
|
|
||||||
|
// nodeOmissionSet holds a set of node IDs of nodes that we should
|
||||||
|
// ignore during blinded path selection.
|
||||||
|
nodeOmissionSet fn.Set[route.Vertex]
|
||||||
}
|
}
|
||||||
|
|
||||||
// blindedHop holds the information about a hop we have selected for a blinded
|
// blindedHop holds the information about a hop we have selected for a blinded
|
||||||
@@ -1253,6 +1258,12 @@ func processNodeForBlindedPath(g Graph, node route.Vertex,
|
|||||||
return nil, false, nil
|
return nil, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have explicitly been told to ignore this node for blinded paths
|
||||||
|
// then we skip it too.
|
||||||
|
if restrictions.nodeOmissionSet.Contains(node) {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
supports, err := supportsRouteBlinding(node)
|
supports, err := supportsRouteBlinding(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
|
|||||||
@@ -3705,7 +3705,26 @@ func TestFindBlindedPaths(t *testing.T) {
|
|||||||
"charlie,eve,bob,dave",
|
"charlie,eve,bob,dave",
|
||||||
})
|
})
|
||||||
|
|
||||||
// 4) Finally, we will test the special case where the destination node
|
// 4) Repeat the above test but instruct the function to never use
|
||||||
|
// charlie.
|
||||||
|
paths, err = ctx.findBlindedPaths(&blindedPathRestrictions{
|
||||||
|
minNumHops: 2,
|
||||||
|
maxNumHops: 3,
|
||||||
|
nodeOmissionSet: fn.NewSet[route.Vertex](
|
||||||
|
ctx.keyFromAlias("charlie"),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// We expect the following paths:
|
||||||
|
// - F, B, D
|
||||||
|
// - E, B, D
|
||||||
|
assertPaths(paths, []string{
|
||||||
|
"frank,bob,dave",
|
||||||
|
"eve,bob,dave",
|
||||||
|
})
|
||||||
|
|
||||||
|
// 5) Finally, we will test the special case where the destination node
|
||||||
// is also the recipient.
|
// is also the recipient.
|
||||||
paths, err = ctx.findBlindedPaths(&blindedPathRestrictions{
|
paths, err = ctx.findBlindedPaths(&blindedPathRestrictions{
|
||||||
minNumHops: 0,
|
minNumHops: 0,
|
||||||
|
|||||||
@@ -664,6 +664,10 @@ type BlindedPathRestrictions struct {
|
|||||||
|
|
||||||
// MaxNumPaths is the maximum number of blinded paths to select.
|
// MaxNumPaths is the maximum number of blinded paths to select.
|
||||||
MaxNumPaths uint8
|
MaxNumPaths uint8
|
||||||
|
|
||||||
|
// NodeOmissionSet is a set of nodes that should not be used within any
|
||||||
|
// of the blinded paths that we generate.
|
||||||
|
NodeOmissionSet fn.Set[route.Vertex]
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindBlindedPaths finds a selection of paths to the destination node that can
|
// FindBlindedPaths finds a selection of paths to the destination node that can
|
||||||
@@ -678,6 +682,7 @@ func (r *ChannelRouter) FindBlindedPaths(destination route.Vertex,
|
|||||||
r.cfg.RoutingGraph, destination, &blindedPathRestrictions{
|
r.cfg.RoutingGraph, destination, &blindedPathRestrictions{
|
||||||
minNumHops: restrictions.MinDistanceFromIntroNode,
|
minNumHops: restrictions.MinDistanceFromIntroNode,
|
||||||
maxNumHops: restrictions.NumHops,
|
maxNumHops: restrictions.NumHops,
|
||||||
|
nodeOmissionSet: restrictions.NodeOmissionSet,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -3236,4 +3236,19 @@ func TestFindBlindedPathsWithMC(t *testing.T) {
|
|||||||
"alice,bob,dave",
|
"alice,bob,dave",
|
||||||
"alice,frank,dave",
|
"alice,frank,dave",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Test that if the user explicitly indicates that we should ignore
|
||||||
|
// the Frank node during path selection, then this is done.
|
||||||
|
routes, err = ctx.router.FindBlindedPaths(
|
||||||
|
dave, 1000, probabilitySrc, &BlindedPathRestrictions{
|
||||||
|
MinDistanceFromIntroNode: 2,
|
||||||
|
NumHops: 2,
|
||||||
|
MaxNumPaths: 3,
|
||||||
|
NodeOmissionSet: fn.NewSet(frank),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assertPaths(routes, []string{
|
||||||
|
"alice,bob,dave",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
@@ -5788,6 +5788,7 @@ func (r *rpcServer) AddInvoice(ctx context.Context,
|
|||||||
MinDistanceFromIntroNode: globalBlindCfg.MinNumRealHops,
|
MinDistanceFromIntroNode: globalBlindCfg.MinNumRealHops,
|
||||||
NumHops: globalBlindCfg.NumHops,
|
NumHops: globalBlindCfg.NumHops,
|
||||||
MaxNumPaths: globalBlindCfg.MaxNumPaths,
|
MaxNumPaths: globalBlindCfg.MaxNumPaths,
|
||||||
|
NodeOmissionSet: fn.NewSet[route.Vertex](),
|
||||||
}
|
}
|
||||||
|
|
||||||
if blind {
|
if blind {
|
||||||
@@ -5802,6 +5803,15 @@ func (r *rpcServer) AddInvoice(ctx context.Context,
|
|||||||
blindingRestrictions.MaxNumPaths =
|
blindingRestrictions.MaxNumPaths =
|
||||||
uint8(*blindCfg.MaxNumPaths)
|
uint8(*blindCfg.MaxNumPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, nodeIDBytes := range blindCfg.NodeOmissionList {
|
||||||
|
vertex, err := route.NewVertexFromBytes(nodeIDBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
blindingRestrictions.NodeOmissionSet.Add(vertex)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if blindingRestrictions.MinDistanceFromIntroNode >
|
if blindingRestrictions.MinDistanceFromIntroNode >
|
||||||
|
|||||||
Reference in new issue
Block a user