multi: add node omission list for blinded paths

This commit is contained in:
Elle Mouton 2024-08-05 14:27:11 +02:00
parent b490deefdf
commit e4619afc08
No known key found for this signature in database
GPG Key ID: D7D916376026F177
10 changed files with 1254 additions and 1142 deletions

View File

@ -110,6 +110,12 @@ var addInvoiceCommand = cli.Command{
"to an invoice. This option will only be " +
"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),
}
@ -221,6 +227,17 @@ func parseBlindedPathCfg(ctx *cli.Context) (*lnrpc.BlindedPathConfig, error) {
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
}

View File

@ -412,6 +412,14 @@
"type": "integer",
"format": "int64",
"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."
}
}
},

File diff suppressed because it is too large Load Diff

View File

@ -3867,6 +3867,12 @@ message BlindedPathConfig {
The maximum number of blinded paths to select and add to an invoice.
*/
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 {

View File

@ -3561,6 +3561,14 @@
"type": "integer",
"format": "int64",
"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."
}
}
},

View File

@ -14,6 +14,7 @@ import (
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/channeldb/models"
"github.com/lightningnetwork/lnd/feature"
"github.com/lightningnetwork/lnd/fn"
"github.com/lightningnetwork/lnd/lnutils"
"github.com/lightningnetwork/lnd/lnwire"
"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
// the path will contain our node along with an introduction node hop.
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
@ -1253,6 +1258,12 @@ func processNodeForBlindedPath(g Graph, node route.Vertex,
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)
if err != nil {
return nil, false, err

View File

@ -3705,7 +3705,26 @@ func TestFindBlindedPaths(t *testing.T) {
"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.
paths, err = ctx.findBlindedPaths(&blindedPathRestrictions{
minNumHops: 0,

View File

@ -664,6 +664,10 @@ type BlindedPathRestrictions struct {
// MaxNumPaths is the maximum number of blinded paths to select.
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
@ -676,8 +680,9 @@ func (r *ChannelRouter) FindBlindedPaths(destination route.Vertex,
// path length restrictions.
paths, err := findBlindedPaths(
r.cfg.RoutingGraph, destination, &blindedPathRestrictions{
minNumHops: restrictions.MinDistanceFromIntroNode,
maxNumHops: restrictions.NumHops,
minNumHops: restrictions.MinDistanceFromIntroNode,
maxNumHops: restrictions.NumHops,
nodeOmissionSet: restrictions.NodeOmissionSet,
},
)
if err != nil {

View File

@ -3236,4 +3236,19 @@ func TestFindBlindedPathsWithMC(t *testing.T) {
"alice,bob,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",
})
}

View File

@ -5788,6 +5788,7 @@ func (r *rpcServer) AddInvoice(ctx context.Context,
MinDistanceFromIntroNode: globalBlindCfg.MinNumRealHops,
NumHops: globalBlindCfg.NumHops,
MaxNumPaths: globalBlindCfg.MaxNumPaths,
NodeOmissionSet: fn.NewSet[route.Vertex](),
}
if blind {
@ -5802,6 +5803,15 @@ func (r *rpcServer) AddInvoice(ctx context.Context,
blindingRestrictions.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 >