From 36e7694e8ee78efacab019136bf664244a8b9899 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Wed, 19 Dec 2018 18:56:43 +0100 Subject: [PATCH] config+pilot: define autopilot.heuristic And validate the config set by the user. --- autopilot/interface.go | 21 ++++++++++++++++ config.go | 22 +++++++++++------ pilot.go | 54 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 7 deletions(-) diff --git a/autopilot/interface.go b/autopilot/interface.go index d905aacf..ac2be6bb 100644 --- a/autopilot/interface.go +++ b/autopilot/interface.go @@ -142,6 +142,27 @@ type AttachmentHeuristic interface { map[NodeID]*NodeScore, error) } +var ( + // availableHeuristics holds all heuristics possible to combine for use + // with the autopilot agent. + availableHeuristics = []AttachmentHeuristic{ + NewPrefAttachment(), + } + + // AvailableHeuristics is a map that holds the name of available + // heuristics to the actual heuristic for easy lookup. It will be + // filled during init(). + AvailableHeuristics = make(map[string]AttachmentHeuristic) +) + +func init() { + // Fill the map from heuristic names to available heuristics for easy + // lookup. + for _, h := range availableHeuristics { + AvailableHeuristics[h.Name()] = h + } +} + // ChannelController is a simple interface that allows an auto-pilot agent to // open a channel within the graph to a target peer, close targeted channels, // or add/remove funds from existing channels via a splice in/out mechanisms. diff --git a/config.go b/config.go index 2441f110..e03a033b 100644 --- a/config.go +++ b/config.go @@ -142,13 +142,14 @@ type bitcoindConfig struct { } type autoPilotConfig struct { - Active bool `long:"active" description:"If the autopilot agent should be active or not."` - MaxChannels int `long:"maxchannels" description:"The maximum number of channels that should be created"` - Allocation float64 `long:"allocation" description:"The percentage of total funds that should be committed to automatic channel establishment"` - MinChannelSize int64 `long:"minchansize" description:"The smallest channel that the autopilot agent should create"` - MaxChannelSize int64 `long:"maxchansize" description:"The largest channel that the autopilot agent should create"` - Private bool `long:"private" description:"Whether the channels created by the autopilot agent should be private or not. Private channels won't be announced to the network."` - MinConfs int32 `long:"minconfs" description:"The minimum number of confirmations each of your inputs in funding transactions created by the autopilot agent must have."` + Active bool `long:"active" description:"If the autopilot agent should be active or not."` + Heuristic map[string]float64 `long:"heuristic" description:"Heuristic to activate, and the weight to give it during scoring."` + MaxChannels int `long:"maxchannels" description:"The maximum number of channels that should be created"` + Allocation float64 `long:"allocation" description:"The percentage of total funds that should be committed to automatic channel establishment"` + MinChannelSize int64 `long:"minchansize" description:"The smallest channel that the autopilot agent should create"` + MaxChannelSize int64 `long:"maxchansize" description:"The largest channel that the autopilot agent should create"` + Private bool `long:"private" description:"Whether the channels created by the autopilot agent should be private or not. Private channels won't be announced to the network."` + MinConfs int32 `long:"minconfs" description:"The minimum number of confirmations each of your inputs in funding transactions created by the autopilot agent must have."` } type torConfig struct { @@ -312,6 +313,9 @@ func loadConfig() (*config, error) { Allocation: 0.6, MinChannelSize: int64(minChanFundingSize), MaxChannelSize: int64(maxFundingAmount), + Heuristic: map[string]float64{ + "preferential": 1.0, + }, }, TrickleDelay: defaultTrickleDelay, InactiveChanTimeout: defaultInactiveChanTimeout, @@ -463,6 +467,10 @@ func loadConfig() (*config, error) { cfg.Autopilot.MaxChannelSize = int64(maxFundingAmount) } + if _, err := validateAtplCfg(cfg.Autopilot); err != nil { + return nil, err + } + // Validate the Tor config parameters. socks, err := lncfg.ParseAddressString( cfg.Tor.SOCKS, strconv.Itoa(defaultTorSOCKSPort), diff --git a/pilot.go b/pilot.go index 3c3e1659..9bfc5cb0 100644 --- a/pilot.go +++ b/pilot.go @@ -14,6 +14,60 @@ import ( "github.com/lightningnetwork/lnd/tor" ) +// validateAtplConfig is a helper method that makes sure the passed +// configuration is sane. Currently it checks that the heuristic configuration +// makes sense. In case the config is valid, it will return a list of +// WeightedHeuristics that can be combined for use with the autopilot agent. +func validateAtplCfg(cfg *autoPilotConfig) ([]*autopilot.WeightedHeuristic, + error) { + + var ( + heuristicsStr string + sum float64 + heuristics []*autopilot.WeightedHeuristic + ) + + // Create a help text that we can return in case the config is not + // correct. + for _, a := range autopilot.AvailableHeuristics { + heuristicsStr += fmt.Sprintf(" '%v' ", a.Name()) + } + availStr := fmt.Sprintf("Avaiblable heuristcs are: [%v]", heuristicsStr) + + // We'll go through the config and make sure all the heuristics exists, + // and that the sum of their weights is 1.0. + for name, weight := range cfg.Heuristic { + a, ok := autopilot.AvailableHeuristics[name] + if !ok { + // No heuristic matching this config option was found. + return nil, fmt.Errorf("Heuristic %v not available. %v", + name, availStr) + } + + // If this heuristic was among the registered ones, we add it + // to the list we'll give to the agent, and keep track of the + // sum of weights. + heuristics = append( + heuristics, + &autopilot.WeightedHeuristic{ + Weight: weight, + AttachmentHeuristic: a, + }, + ) + sum += weight + } + + // Check found heuristics. We must have at least one to operate. + if len(heuristics) == 0 { + return nil, fmt.Errorf("No active heuristics. %v", availStr) + } + + if sum != 1.0 { + return nil, fmt.Errorf("Heuristic weights must sum to 1.0") + } + return heuristics, nil +} + // chanController is an implementation of the autopilot.ChannelController // interface that's backed by a running lnd instance. type chanController struct {