exclude-from and exclude-to

This commit is contained in:
ziggie 2022-11-12 00:35:46 +01:00
parent 64b23b3017
commit 916e6b8627
No known key found for this signature in database
GPG Key ID: 61D302CA09A9C7B5
3 changed files with 117 additions and 102 deletions

View File

@ -81,19 +81,21 @@ in `~/go/bin/linux_arm`.
-b, --probe-steps= if the payment fails at the last hop try to probe lower amount using this many steps -b, --probe-steps= if the payment fails at the last hop try to probe lower amount using this many steps
--allow-rapid-rebalance if a rebalance succeeds the route will be used for further rebalances until criteria for channels is not satifsied --allow-rapid-rebalance if a rebalance succeeds the route will be used for further rebalances until criteria for channels is not satifsied
--min-amount= if probing is enabled this will be the minimum amount to try --min-amount= if probing is enabled this will be the minimum amount to try
-i, --exclude-channel-in= don't use this channel as incoming (can be specified multiple times) -i, --exclude-channel-in= (DEPRECATED) don't use this channel as incoming (can be specified multiple times)
-o, --exclude-channel-out= don't use this channel as outgoing (can be specified multiple times) -o, --exclude-channel-out= (DEPRECATED) don't use this channel as outgoing (can be specified multiple times)
--exclude-from= don't use this node or channel as source (can be specified multiple times)
--exclude-to= don't use this node or channel as target (can be specified multiple times)
-e, --exclude-channel= (DEPRECATED) don't use this channel at all (can be specified multiple times) -e, --exclude-channel= (DEPRECATED) don't use this channel at all (can be specified multiple times)
-d, --exclude-node= (DEPRECATED) don't use this node for routing (can be specified multiple times) -d, --exclude-node= (DEPRECATED) don't use this node for routing (can be specified multiple times)
--exclude= don't use this node or your channel for routing (can be specified multiple times) --exclude= don't use this node or your channel for routing (can be specified multiple times)
--to= try only this channel or node as target (should satisfy other constraints too; can be specified multiple times) --to= try only this channel or node as target (should satisfy other constraints too; can be specified multiple times)
--from= try only this channel or node as source (should satisfy other constraints too; can be specified multiple times) --from= try only this channel or node as source (should satisfy other constraints too; can be specified multiple times)
--fail-tolerance= if a channel failed before during this rebalance but chosen again by lnd, and the forward amount differs by less than this ppm, exclude the channel --fail-tolerance= a payment that differs from the prior attempt by this ppm will be cancelled
--allow-unbalance-from let the source channel go below 50% local liquidity, use if you want to drain a channel; you should also set --pfrom to >50 --allow-unbalance-from let the source channel go below 50% local liquidity, use if you want to drain a channel; you should also set --pfrom to >50
--allow-unbalance-to let the target channel go above 50% local liquidity, use if you want to refill a channel; you should also set --pto to >50 --allow-unbalance-to let the target channel go above 50% local liquidity, use if you want to refill a channel; you should also set --pto to >50
-s, --stat= save successful rebalance information to the specified CSV file -s, --stat= save successful rebalance information to the specified CSV file
--node-cache-filename= save and load other nodes information to this file, improves cold start performance --node-cache-filename= save and load other nodes information to this file, improves cold start performance
--node-cache-lifetime= nodes with last update older than this time (in minutes) will be removed from cache after loading it (default: 1440) --node-cache-lifetime= nodes with last update older than this time (in minutes) will be removed from cache after loading it
--node-cache-info show red and cyan 'x' characters in routes to indicate node cache misses and hits respectively --node-cache-info show red and cyan 'x' characters in routes to indicate node cache misses and hits respectively
--timeout-rebalance= max rebalance session time in minutes --timeout-rebalance= max rebalance session time in minutes
--timeout-attempt= max attempt time in minutes --timeout-attempt= max attempt time in minutes

View File

@ -63,10 +63,11 @@ func parseNodeChannelIDs(ids []string) (chans map[uint64]struct{}, nodes [][]byt
func (r *regolancer) getChannelCandidates(fromPerc, toPerc, amount int64) error { func (r *regolancer) getChannelCandidates(fromPerc, toPerc, amount int64) error {
for _, c := range r.channels { for _, c := range r.channels {
if _, ok := r.excludeBoth[c.ChanId]; ok { if _, ok := r.excludeBoth[c.ChanId]; ok {
continue continue
} }
if _, ok := r.excludeIn[c.ChanId]; !ok { if _, ok := r.excludeTo[c.ChanId]; !ok {
if _, ok := r.toChannelId[c.ChanId]; ok || len(r.toChannelId) == 0 { if _, ok := r.toChannelId[c.ChanId]; ok || len(r.toChannelId) == 0 {
if c.LocalBalance < c.Capacity*toPerc/100 { if c.LocalBalance < c.Capacity*toPerc/100 {
r.toChannels = append(r.toChannels, c) r.toChannels = append(r.toChannels, c)
@ -74,7 +75,7 @@ func (r *regolancer) getChannelCandidates(fromPerc, toPerc, amount int64) error
} }
} }
if _, ok := r.excludeOut[c.ChanId]; !ok { if _, ok := r.excludeFrom[c.ChanId]; !ok {
if _, ok := r.fromChannelId[c.ChanId]; ok || len(r.fromChannelId) == 0 { if _, ok := r.fromChannelId[c.ChanId]; ok || len(r.fromChannelId) == 0 {
if c.RemoteBalance < c.Capacity*fromPerc/100 { if c.RemoteBalance < c.Capacity*fromPerc/100 {
r.fromChannels = append(r.fromChannels, c) r.fromChannels = append(r.fromChannels, c)
@ -194,3 +195,43 @@ func parseScid(chanId string) int64 {
return int64(scId.ToUint64()) return int64(scId.ToUint64())
} }
func (r *regolancer) getChannelForPeer(ctx context.Context, node []byte) []*lnrpc.Channel {
channels, err := r.lnClient.ListChannels(ctx, &lnrpc.ListChannelsRequest{ActiveOnly: true, PublicOnly: true, Peer: node})
if err != nil {
log.Fatalf("Error fetching channels when filtering for node \"%x\": %s", node, err)
}
return channels.Channels
}
func (r *regolancer) filterChannels(ctx context.Context, nodeChannelIDs []string) (channels map[uint64]struct{}) {
channels = map[uint64]struct{}{}
chans, nodes, err := parseNodeChannelIDs(nodeChannelIDs)
if err != nil {
log.Fatal("Error parsing node/channel list:", err)
}
// Needed bc of deprecated ExcludeChannelsIn feature
for id := range chans {
if _, ok := channels[id]; !ok {
channels[id] = struct{}{}
}
}
for _, node := range nodes {
chans := r.getChannelForPeer(ctx, node)
for _, c := range chans {
if _, ok := channels[c.ChanId]; !ok {
channels[c.ChanId] = struct{}{}
}
}
}
return
}

94
main.go
View File

@ -38,8 +38,10 @@ type configParams struct {
ProbeSteps int `short:"b" long:"probe-steps" description:"if the payment fails at the last hop try to probe lower amount using this many steps" json:"probe_steps" toml:"probe_steps"` ProbeSteps int `short:"b" long:"probe-steps" description:"if the payment fails at the last hop try to probe lower amount using this many steps" json:"probe_steps" toml:"probe_steps"`
AllowRapidRebalance bool `long:"allow-rapid-rebalance" description:"if a rebalance succeeds the route will be used for further rebalances until criteria for channels is not satifsied" json:"allow_rapid_rebalance" toml:"allow_rapid_rebalance"` AllowRapidRebalance bool `long:"allow-rapid-rebalance" description:"if a rebalance succeeds the route will be used for further rebalances until criteria for channels is not satifsied" json:"allow_rapid_rebalance" toml:"allow_rapid_rebalance"`
MinAmount int64 `long:"min-amount" description:"if probing is enabled this will be the minimum amount to try" json:"min_amount" toml:"min_amount"` MinAmount int64 `long:"min-amount" description:"if probing is enabled this will be the minimum amount to try" json:"min_amount" toml:"min_amount"`
ExcludeChannelsIn []string `short:"i" long:"exclude-channel-in" description:"don't use this channel as incoming (can be specified multiple times)" json:"exclude_channels_in" toml:"exclude_channels_in"` ExcludeChannelsIn []string `short:"i" long:"exclude-channel-in" description:"(DEPRECATED) don't use this channel as incoming (can be specified multiple times)" json:"exclude_channels_in" toml:"exclude_channels_in"`
ExcludeChannelsOut []string `short:"o" long:"exclude-channel-out" description:"don't use this channel as outgoing (can be specified multiple times)" json:"exclude_channels_out" toml:"exclude_channels_out"` ExcludeChannelsOut []string `short:"o" long:"exclude-channel-out" description:"(DEPRECATED) don't use this channel as outgoing (can be specified multiple times)" json:"exclude_channels_out" toml:"exclude_channels_out"`
ExcludeFrom []string `long:"exclude-from" description:"don't use this node or channel as source (can be specified multiple times)" json:"exclude_from" toml:"exclude_from"`
ExcludeTo []string `long:"exclude-to" description:"don't use this node or channel as target (can be specified multiple times)" json:"exclude_to" toml:"exclude_to"`
ExcludeChannels []string `short:"e" long:"exclude-channel" description:"(DEPRECATED) don't use this channel at all (can be specified multiple times)" json:"exclude_channels" toml:"exclude_channels"` ExcludeChannels []string `short:"e" long:"exclude-channel" description:"(DEPRECATED) don't use this channel at all (can be specified multiple times)" json:"exclude_channels" toml:"exclude_channels"`
ExcludeNodes []string `short:"d" long:"exclude-node" description:"(DEPRECATED) don't use this node for routing (can be specified multiple times)" json:"exclude_nodes" toml:"exclude_nodes"` ExcludeNodes []string `short:"d" long:"exclude-node" description:"(DEPRECATED) don't use this node for routing (can be specified multiple times)" json:"exclude_nodes" toml:"exclude_nodes"`
Exclude []string `long:"exclude" description:"don't use this node or your channel for routing (can be specified multiple times)" json:"exclude" toml:"exclude"` Exclude []string `long:"exclude" description:"don't use this node or your channel for routing (can be specified multiple times)" json:"exclude" toml:"exclude"`
@ -89,8 +91,8 @@ type regolancer struct {
nodeCache map[string]cachedNodeInfo nodeCache map[string]cachedNodeInfo
chanCache map[uint64]*lnrpc.ChannelEdge chanCache map[uint64]*lnrpc.ChannelEdge
failureCache map[string]failedRoute failureCache map[string]failedRoute
excludeIn map[uint64]struct{} excludeTo map[uint64]struct{}
excludeOut map[uint64]struct{} excludeFrom map[uint64]struct{}
excludeBoth map[uint64]struct{} excludeBoth map[uint64]struct{}
excludeNodes [][]byte excludeNodes [][]byte
statFilename string statFilename string
@ -407,39 +409,43 @@ func preflightChecks(params *configParams) error {
if (params.RelAmountFrom > 0 || params.RelAmountTo > 0) && params.AllowRapidRebalance { if (params.RelAmountFrom > 0 || params.RelAmountTo > 0) && params.AllowRapidRebalance {
return fmt.Errorf("use either relative amounts or rapid rebalance but not both") return fmt.Errorf("use either relative amounts or rapid rebalance but not both")
} }
if params.NodeCacheLifetime == 0 { if params.NodeCacheLifetime == 0 {
params.NodeCacheLifetime = 1440 params.NodeCacheLifetime = 1440
} }
if len(params.ExcludeChannels) > 0 || len(params.ExcludeNodes) > 0 { if len(params.ExcludeChannels) > 0 || len(params.ExcludeNodes) > 0 {
log.Print(infoColor("--exclude-channel and exclude_channel parameter are deprecated, use --exclude or exclude parameter instead for both channels and nodes")) log.Print(infoColor("--exclude-channel and exclude_channel parameter are deprecated, use --exclude or exclude parameter instead for both channels and nodes"))
if len(params.Exclude) > 0 { if len(params.Exclude) > 0 {
return fmt.Errorf("can't use --exclude and --exclude-channel/--exclude-node (or config parameters) at the same time") return fmt.Errorf("can't use --exclude and --exclude-channel/--exclude-node (or config parameters) at the same time")
} }
} }
if params.AllowUnbalanceFrom || params.AllowUnbalanceTo { if params.AllowUnbalanceFrom || params.AllowUnbalanceTo {
log.Print(infoColor("--allow-unbalance-from/to are deprecated and enabled by default, please remove them from your config or command line parameters")) log.Print(infoColor("--allow-unbalance-from/to are deprecated and enabled by default, please remove them from your config or command line parameters"))
} }
if len(params.ExcludeChannelsIn) > 0 {
log.Print(infoColor("--exclude-channel-in are deprecated use --exclude-to instead, please remove them from your config or command line parameters"))
if len(params.ExcludeTo) > 0 {
return fmt.Errorf("can't use --exclude-to and --exclude-channel-in (or config parameters) at the same time")
}
}
if len(params.ExcludeChannelsOut) > 0 {
log.Print(infoColor("--exclude-channel-out are deprecated use --exclude-from instead, please remove them from your config or command line parameters"))
if len(params.ExcludeFrom) > 0 {
return fmt.Errorf("can't use --exclude-from and --exclude-channel-out (or config parameters) at the same time")
}
}
if params.TimeoutAttempt == 0 { if params.TimeoutAttempt == 0 {
params.TimeoutAttempt = 5 params.TimeoutAttempt = 5
} }
if params.TimeoutRebalance == 0 { if params.TimeoutRebalance == 0 {
params.TimeoutRebalance = 360 params.TimeoutRebalance = 360
} }
if params.TimeoutInfo == 0 { if params.TimeoutInfo == 0 {
params.TimeoutInfo = 30 params.TimeoutInfo = 30
} }
if params.TimeoutRoute == 0 { if params.TimeoutRoute == 0 {
params.TimeoutRoute = 30 params.TimeoutRoute = 30
} }
return nil return nil
} }
@ -506,67 +512,33 @@ func main() {
if err != nil { if err != nil {
log.Fatal("Error listing own channels: ", err) log.Fatal("Error listing own channels: ", err)
} }
if len(params.From) > 0 { if len(params.From) > 0 {
chans, nodes, err := parseNodeChannelIDs(params.From) r.fromChannelId = r.filterChannels(infoCtx, params.From)
if err != nil {
log.Fatal("Error parsing source node/channel list:", err)
}
r.fromChannelId = chans
for _, node := range nodes {
channels, err := r.lnClient.ListChannels(infoCtx, &lnrpc.ListChannelsRequest{ActiveOnly: true, PublicOnly: true, Peer: node})
if err != nil {
log.Fatalf("Error fetching channels when filtering for source node \"%x\": %s", node, err)
}
for _, c := range channels.Channels {
if _, ok := r.fromChannelId[c.ChanId]; !ok {
r.fromChannelId[c.ChanId] = struct{}{}
}
}
}
if len(r.fromChannelId) == 0 { if len(r.fromChannelId) == 0 {
log.Fatal("No source nodes/channels selected, check if the ID is correct and node is online") log.Fatal("No source nodes/channels selected, check if the ID is correct and node is online")
} }
} }
if len(params.To) > 0 { if len(params.To) > 0 {
chans, nodes, err := parseNodeChannelIDs(params.To) r.toChannelId = r.filterChannels(infoCtx, params.To)
if err != nil {
log.Fatal("Error parsing target node/channel list:", err)
}
r.toChannelId = chans
for _, node := range nodes {
channels, err := r.lnClient.ListChannels(infoCtx, &lnrpc.ListChannelsRequest{ActiveOnly: true, PublicOnly: true, Peer: node})
if err != nil {
log.Fatalf("Error fetching channels when filtering for target node \"%x\": %s", node, err)
}
for _, c := range channels.Channels {
if _, ok := r.toChannelId[c.ChanId]; !ok {
r.toChannelId[c.ChanId] = struct{}{}
}
}
}
if len(r.toChannelId) == 0 { if len(r.toChannelId) == 0 {
log.Fatal("No target nodes/channels selected, check if the ID is correct and node is online") log.Fatal("No target nodes/channels selected, check if the ID is correct and node is online")
} }
} }
r.excludeIn = makeChanSet(convertChanStringToInt(params.ExcludeChannelsIn)) if len(params.ExcludeFrom) > 0 {
r.excludeOut = makeChanSet(convertChanStringToInt(params.ExcludeChannelsOut)) r.excludeFrom = r.filterChannels(infoCtx, params.ExcludeFrom)
r.excludeBoth = makeChanSet(convertChanStringToInt(params.ExcludeChannels)) } else {
r.excludeFrom = makeChanSet(convertChanStringToInt(params.ExcludeChannelsOut))
}
if len(params.ExcludeTo) > 0 {
r.excludeTo = r.filterChannels(infoCtx, params.ExcludeTo)
} else {
r.excludeTo = makeChanSet(convertChanStringToInt(params.ExcludeChannelsIn))
}
r.excludeBoth = makeChanSet(convertChanStringToInt(params.ExcludeChannels))
err = r.makeNodeList(params.ExcludeNodes) err = r.makeNodeList(params.ExcludeNodes)
if err != nil { if err != nil {
log.Fatal("Error parsing excluded node list: ", err) log.Fatal("Error parsing excluded node list: ", err)