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

@ -61,45 +61,47 @@ in `~/go/bin/linux_arm`.
# Parameters # Parameters
``` ```
-f, --config= config file path -f, --config= config file path
-c, --connect= connect to lnd using host:port -c, --connect= connect to lnd using host:port
-t, --tlscert= path to tls.cert to connect -t, --tlscert= path to tls.cert to connect
--macaroon-dir= path to the macaroon directory --macaroon-dir= path to the macaroon directory
--macaroon-filename= macaroon filename --macaroon-filename= macaroon filename
-n, --network= bitcoin network to use -n, --network= bitcoin network to use
--pfrom= channels with less than this inbound liquidity percentage will be considered as source channels --pfrom= channels with less than this inbound liquidity percentage will be considered as source channels
--pto= channels with less than this outbound liquidity percentage will be considered as target channels --pto= channels with less than this outbound liquidity percentage will be considered as target channels
-p, --perc= use this value as both pfrom and pto from above -p, --perc= use this value as both pfrom and pto from above
-a, --amount= amount to rebalance -a, --amount= amount to rebalance
--rel-amount-to= calculate amount as the target channel capacity fraction (for example, 0.2 means you want to achieve at most 20% target channel local balance) --rel-amount-to= calculate amount as the target channel capacity fraction (for example, 0.2 means you want to achieve at most 20% target channel local balance)
--rel-amount-from= calculate amount as the source channel capacity fraction (for example, 0.2 means you want to achieve at most 20% source channel remote balance) --rel-amount-from= calculate amount as the source channel capacity fraction (for example, 0.2 means you want to achieve at most 20% source channel remote balance)
-r, --econ-ratio= economical ratio for fee limit calculation as a multiple of target channel fee (for example, 0.5 means you want to pay at max half the fee you -r, --econ-ratio= economical ratio for fee limit calculation as a multiple of target channel fee (for example, 0.5 means you want to pay at max half the fee you
might earn for routing out of the target channel) might earn for routing out of the target channel)
--econ-ratio-max-ppm= limits the max fee ppm for a rebalance when using econ ratio --econ-ratio-max-ppm= limits the max fee ppm for a rebalance when using econ ratio
-F, --fee-limit-ppm= don't consider the target channel fee and use this max fee ppm instead (can rebalance at a loss, be careful) -F, --fee-limit-ppm= don't consider the target channel fee and use this max fee ppm instead (can rebalance at a loss, be careful)
-l, --lost-profit also consider the outbound channel fees when looking for profitable routes so that outbound_fee+inbound_fee < route_fee -l, --lost-profit also consider the outbound channel fees when looking for profitable routes so that outbound_fee+inbound_fee < route_fee
-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)
-e, --exclude-channel= (DEPRECATED) don't use this channel at all (can be specified multiple times) --exclude-from= don't use this node or channel as source (can be specified multiple times)
-d, --exclude-node= (DEPRECATED) don't use this node for routing (can be specified multiple times) --exclude-to= don't use this node or channel as target (can be specified multiple times)
--exclude= don't use this node or your channel for routing (can be specified multiple times) -e, --exclude-channel= (DEPRECATED) don't use this channel at all (can be specified multiple times)
--to= try only this channel or node as target (should satisfy other constraints too; can be specified multiple times) -d, --exclude-node= (DEPRECATED) don't use this node for routing (can be specified multiple times)
--from= try only this channel or node as source (should satisfy other constraints too; can be specified multiple times) --exclude= don't use this node or your channel for routing (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 --to= try only this channel or node as target (should satisfy other constraints too; can be specified multiple times)
--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 --from= try only this channel or node as source (should satisfy other constraints too; can be specified multiple times)
--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 --fail-tolerance= a payment that differs from the prior attempt by this ppm will be cancelled
-s, --stat= save successful rebalance information to the specified CSV file --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
--node-cache-filename= save and load other nodes information to this file, improves cold start performance --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
--node-cache-lifetime= nodes with last update older than this time (in minutes) will be removed from cache after loading it (default: 1440) -s, --stat= save successful rebalance information to the specified CSV file
--node-cache-info show red and cyan 'x' characters in routes to indicate node cache misses and hits respectively --node-cache-filename= save and load other nodes information to this file, improves cold start performance
--timeout-rebalance= max rebalance session time in minutes --node-cache-lifetime= nodes with last update older than this time (in minutes) will be removed from cache after loading it
--timeout-attempt= max attempt time in minutes --node-cache-info show red and cyan 'x' characters in routes to indicate node cache misses and hits respectively
--timeout-info= max general info query time (local channels, node id etc.) in seconds --timeout-rebalance= max rebalance session time in minutes
--timeout-route= max channel selection and route query time in seconds --timeout-attempt= max attempt time in minutes
-v, --version show program version and exit --timeout-info= max general info query time (local channels, node id etc.) in seconds
--timeout-route= max channel selection and route query time in seconds
-v, --version show program version and exit
``` ```
Look in `config.json.sample` or `config.toml.sample` for corresponding keys, Look in `config.json.sample` or `config.toml.sample` for corresponding keys,

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)