From 6130189d95fa5cd396f58b84012ca1d2f35c3e6e Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Thu, 22 Nov 2018 23:18:09 +0100 Subject: [PATCH] autopilot/interface+agent: remove Select --- autopilot/agent_test.go | 6 -- autopilot/interface.go | 11 --- autopilot/prefattach.go | 181 ---------------------------------------- 3 files changed, 198 deletions(-) diff --git a/autopilot/agent_test.go b/autopilot/agent_test.go index 9cf8aae28..e3aee2642 100644 --- a/autopilot/agent_test.go +++ b/autopilot/agent_test.go @@ -66,12 +66,6 @@ type directiveArg struct { nodes map[NodeID]struct{} } -func (m *mockHeuristic) Select(self *btcec.PublicKey, graph ChannelGraph, - amtToUse btcutil.Amount, numChans uint32, - skipChans map[NodeID]struct{}) ([]AttachmentDirective, error) { - return nil, nil -} - func (m *mockHeuristic) NodeScores(g ChannelGraph, chans []Channel, fundsAvailable btcutil.Amount, nodes map[NodeID]struct{}) ( map[NodeID]*AttachmentDirective, error) { diff --git a/autopilot/interface.go b/autopilot/interface.go index 492a2ba3f..e0d0cb90d 100644 --- a/autopilot/interface.go +++ b/autopilot/interface.go @@ -121,17 +121,6 @@ type AttachmentHeuristic interface { // ideal state. NeedMoreChans(chans []Channel, balance btcutil.Amount) (btcutil.Amount, uint32, bool) - // Select is a method that given the current state of the channel - // graph, a set of nodes to ignore, and an amount of available funds, - // should return a set of attachment directives which describe which - // additional channels should be opened within the graph to push the - // heuristic back towards its equilibrium state. The numNewChans - // argument represents the additional number of channels that should be - // open. - Select(self *btcec.PublicKey, graph ChannelGraph, - amtToUse btcutil.Amount, numNewChans uint32, - skipNodes map[NodeID]struct{}) ([]AttachmentDirective, error) - // NodeScores is a method that given the current channel graph, current // set of local channels and funds available, scores the given nodes // according to the preference of opening a channel with them. The diff --git a/autopilot/prefattach.go b/autopilot/prefattach.go index 59f89bb26..d90437b89 100644 --- a/autopilot/prefattach.go +++ b/autopilot/prefattach.go @@ -1,8 +1,6 @@ package autopilot import ( - "bytes" - "fmt" prand "math/rand" "net" "time" @@ -72,185 +70,6 @@ func NewNodeID(pub *btcec.PublicKey) NodeID { return n } -// shuffleCandidates shuffles the set of candidate nodes for preferential -// attachment in order to break any ordering already enforced by the sorted -// order of the public key for each node. To shuffle the set of candidates, we -// use a version of the Fisher–Yates shuffle algorithm. -func shuffleCandidates(candidates []Node) []Node { - shuffledNodes := make([]Node, len(candidates)) - perm := prand.Perm(len(candidates)) - - for i, v := range perm { - shuffledNodes[v] = candidates[i] - } - - return shuffledNodes -} - -// Select returns a candidate set of attachment directives that should be -// executed based on the current internal state, the state of the channel -// graph, the set of nodes we should exclude, and the amount of funds -// available. The heuristic employed by this method is one that attempts to -// promote a scale-free network globally, via local attachment preferences for -// new nodes joining the network with an amount of available funds to be -// allocated to channels. Specifically, we consider the degree of each node -// (and the flow in/out of the node available via its open channels) and -// utilize the Barabási–Albert model to drive our recommended attachment -// heuristics. If implemented globally for each new participant, this results -// in a channel graph that is scale-free and follows a power law distribution -// with k=-3. -// -// NOTE: This is a part of the AttachmentHeuristic interface. -func (p *ConstrainedPrefAttachment) Select(self *btcec.PublicKey, g ChannelGraph, - fundsAvailable btcutil.Amount, numNewChans uint32, - skipNodes map[NodeID]struct{}) ([]AttachmentDirective, error) { - - // TODO(roasbeef): rename? - - var directives []AttachmentDirective - - if fundsAvailable < p.constraints.MinChanSize { - return directives, nil - } - - selfPubBytes := self.SerializeCompressed() - - // We'll continue our attachment loop until we've exhausted the current - // amount of available funds. - visited := make(map[NodeID]struct{}) - for i := uint32(0); i < numNewChans; i++ { - // selectionSlice will be used to randomly select a node - // according to a power law distribution. For each connected - // edge, we'll add an instance of the node to this slice. Thus, - // for a given node, the probability that we'll attach to it - // is: k_i / sum(k_j), where k_i is the degree of the target - // node, and k_j is the degree of all other nodes i != j. This - // implements the classic Barabási–Albert model for - // preferential attachment. - var selectionSlice []Node - - // For each node, and each channel that the node has, we'll add - // an instance of that node to the selection slice above. - // This'll slice where the frequency of each node is equivalent - // to the number of channels that connect to it. - // - // TODO(roasbeef): add noise to make adversarially resistant? - if err := g.ForEachNode(func(node Node) error { - nID := NodeID(node.PubKey()) - - // Once a node has already been attached to, we'll - // ensure that it isn't factored into any further - // decisions within this round. - if _, ok := visited[nID]; ok { - return nil - } - - // If we come across ourselves, them we'll continue in - // order to avoid attempting to make a channel with - // ourselves. - if bytes.Equal(nID[:], selfPubBytes) { - return nil - } - - // Additionally, if this node is in the blacklist, then - // we'll skip it. - if _, ok := skipNodes[nID]; ok { - return nil - } - - // For initial bootstrap purposes, if a node doesn't - // have any channels, then we'll ensure that it has at - // least one item in the selection slice. - // - // TODO(roasbeef): make conditional? - selectionSlice = append(selectionSlice, node) - - // For each active channel the node has, we'll add an - // additional channel to the selection slice to - // increase their weight. - if err := node.ForEachChannel(func(channel ChannelEdge) error { - selectionSlice = append(selectionSlice, node) - return nil - }); err != nil { - return err - } - - return nil - }); err != nil { - return nil, err - } - - // If no nodes at all were accumulated, then we'll exit early - // as there are no eligible candidates. - if len(selectionSlice) == 0 { - break - } - - // Given our selection slice, we'll now generate a random index - // into this slice. The node we select will be recommended by - // us to create a channel to. - candidates := shuffleCandidates(selectionSlice) - selectedIndex := prand.Int31n(int32(len(candidates))) - selectedNode := candidates[selectedIndex] - - // TODO(roasbeef): cap on num channels to same participant? - - // With the node selected, we'll add this (node, amount) tuple - // to out set of recommended directives. - pubBytes := selectedNode.PubKey() - nID := NodeID(pubBytes) - directives = append(directives, AttachmentDirective{ - NodeID: nID, - Addrs: selectedNode.Addrs(), - }) - - // With the node selected, we'll add it to the set of visited - // nodes to avoid attaching to it again. - visited[nID] = struct{}{} - } - - numSelectedNodes := int64(len(directives)) - switch { - // If we have enough available funds to distribute the maximum channel - // size for each of the selected peers to attach to, then we'll - // allocate the maximum amount to each peer. - case int64(fundsAvailable) >= numSelectedNodes*int64(p.constraints.MaxChanSize): - for i := 0; i < int(numSelectedNodes); i++ { - directives[i].ChanAmt = p.constraints.MaxChanSize - } - - return directives, nil - - // Otherwise, we'll greedily allocate our funds to the channels - // successively until we run out of available funds, or can't create a - // channel above the min channel size. - case int64(fundsAvailable) < numSelectedNodes*int64(p.constraints.MaxChanSize): - i := 0 - for fundsAvailable > p.constraints.MinChanSize { - // We'll attempt to allocate the max channel size - // initially. If we don't have enough funds to do this, - // then we'll allocate the remainder of the funds - // available to the channel. - delta := p.constraints.MaxChanSize - if fundsAvailable-delta < 0 { - delta = fundsAvailable - } - - directives[i].ChanAmt = delta - - fundsAvailable -= delta - i++ - } - - // We'll slice the initial set of directives to properly - // reflect the amount of funds we were able to allocate. - return directives[:i:i], nil - - default: - return nil, fmt.Errorf("err") - } -} - // NodeScores is a method that given the current channel graph, current set of // local channels and funds available, scores the given nodes according the the // preference of opening a channel with them.