autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
package autopilot
|
|
|
|
|
|
|
|
import (
|
2018-11-23 01:18:09 +03:00
|
|
|
"bytes"
|
2018-11-23 01:18:09 +03:00
|
|
|
"fmt"
|
2018-11-23 01:18:09 +03:00
|
|
|
"math/rand"
|
2018-08-07 04:58:36 +03:00
|
|
|
"net"
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
"sync"
|
|
|
|
"sync/atomic"
|
2018-11-23 01:18:09 +03:00
|
|
|
"time"
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
|
2018-06-05 04:34:16 +03:00
|
|
|
"github.com/btcsuite/btcd/btcec"
|
|
|
|
"github.com/btcsuite/btcutil"
|
2018-07-31 10:17:17 +03:00
|
|
|
"github.com/davecgh/go-spew/spew"
|
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
)
|
|
|
|
|
2018-01-30 03:07:26 +03:00
|
|
|
// Config couples all the items that an autopilot agent needs to function.
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
// All items within the struct MUST be populated for the Agent to be able to
|
|
|
|
// carry out its duties.
|
|
|
|
type Config struct {
|
|
|
|
// Self is the identity public key of the Lightning Network node that
|
|
|
|
// is being driven by the agent. This is used to ensure that we don't
|
|
|
|
// accidentally attempt to open a channel with ourselves.
|
|
|
|
Self *btcec.PublicKey
|
|
|
|
|
|
|
|
// Heuristic is an attachment heuristic which will govern to whom we
|
|
|
|
// open channels to, and also what those channels look like in terms of
|
|
|
|
// desired capacity. The Heuristic will take into account the current
|
|
|
|
// state of the graph, our set of open channels, and the amount of
|
|
|
|
// available funds when determining how channels are to be opened.
|
|
|
|
// Additionally, a heuristic make also factor in extra-graph
|
|
|
|
// information in order to make more pertinent recommendations.
|
|
|
|
Heuristic AttachmentHeuristic
|
|
|
|
|
|
|
|
// ChanController is an interface that is able to directly manage the
|
|
|
|
// creation, closing and update of channels within the network.
|
|
|
|
ChanController ChannelController
|
|
|
|
|
2018-08-07 04:58:36 +03:00
|
|
|
// ConnectToPeer attempts to connect to the peer using one of its
|
|
|
|
// advertised addresses. The boolean returned signals whether the peer
|
|
|
|
// was already connected.
|
|
|
|
ConnectToPeer func(*btcec.PublicKey, []net.Addr) (bool, error)
|
|
|
|
|
|
|
|
// DisconnectPeer attempts to disconnect the peer with the given public
|
|
|
|
// key.
|
|
|
|
DisconnectPeer func(*btcec.PublicKey) error
|
|
|
|
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
// WalletBalance is a function closure that should return the current
|
2018-10-09 19:28:34 +03:00
|
|
|
// available balance of the backing wallet.
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
WalletBalance func() (btcutil.Amount, error)
|
|
|
|
|
|
|
|
// Graph is an abstract channel graph that the Heuristic and the Agent
|
|
|
|
// will use to make decisions w.r.t channel allocation and placement
|
|
|
|
// within the graph.
|
|
|
|
Graph ChannelGraph
|
|
|
|
|
2018-11-23 01:18:08 +03:00
|
|
|
// Constraints is the set of constraints the autopilot must adhere to
|
|
|
|
// when opening channels.
|
2018-12-19 16:54:53 +03:00
|
|
|
Constraints AgentConstraints
|
2018-03-11 03:46:38 +03:00
|
|
|
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
// TODO(roasbeef): add additional signals from fee rates and revenue of
|
|
|
|
// currently opened channels
|
|
|
|
}
|
|
|
|
|
|
|
|
// channelState is a type that represents the set of active channels of the
|
2018-10-09 19:28:34 +03:00
|
|
|
// backing LN node that the Agent should be aware of. This type contains a few
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
// helper utility methods.
|
|
|
|
type channelState map[lnwire.ShortChannelID]Channel
|
|
|
|
|
2017-08-16 04:23:52 +03:00
|
|
|
// Channels returns a slice of all the active channels.
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
func (c channelState) Channels() []Channel {
|
|
|
|
chans := make([]Channel, 0, len(c))
|
|
|
|
for _, channel := range c {
|
|
|
|
chans = append(chans, channel)
|
|
|
|
}
|
|
|
|
return chans
|
|
|
|
}
|
|
|
|
|
|
|
|
// ConnectedNodes returns the set of nodes we currently have a channel with.
|
|
|
|
// This information is needed as we want to avoid making repeated channels with
|
|
|
|
// any node.
|
|
|
|
func (c channelState) ConnectedNodes() map[NodeID]struct{} {
|
|
|
|
nodes := make(map[NodeID]struct{})
|
|
|
|
for _, channels := range c {
|
|
|
|
nodes[channels.Node] = struct{}{}
|
|
|
|
}
|
2017-08-22 08:20:54 +03:00
|
|
|
|
|
|
|
// TODO(roasbeef): add outgoing, nodes, allow incoming and outgoing to
|
|
|
|
// per node
|
|
|
|
// * only add node is chan as funding amt set
|
|
|
|
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
return nodes
|
|
|
|
}
|
|
|
|
|
|
|
|
// Agent implements a closed-loop control system which seeks to autonomously
|
|
|
|
// optimize the allocation of satoshis within channels throughput the network's
|
|
|
|
// channel graph. An agent is configurable by swapping out different
|
|
|
|
// AttachmentHeuristic strategies. The agent uses external signals such as the
|
|
|
|
// wallet balance changing, or new channels being opened/closed for the local
|
|
|
|
// node as an indicator to re-examine its internal state, and the amount of
|
|
|
|
// available funds in order to make updated decisions w.r.t the channel graph.
|
|
|
|
// The Agent will automatically open, close, and splice in/out channel as
|
|
|
|
// necessary for it to step closer to its optimal state.
|
|
|
|
//
|
|
|
|
// TODO(roasbeef): prob re-word
|
|
|
|
type Agent struct {
|
|
|
|
// Only to be used atomically.
|
|
|
|
started uint32
|
|
|
|
stopped uint32
|
|
|
|
|
|
|
|
// cfg houses the configuration state of the Ant.
|
|
|
|
cfg Config
|
|
|
|
|
|
|
|
// chanState tracks the current set of open channels.
|
2018-12-19 16:54:55 +03:00
|
|
|
chanState channelState
|
|
|
|
chanStateMtx sync.Mutex
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
|
|
|
|
// stateUpdates is a channel that any external state updates that may
|
|
|
|
// affect the heuristics of the agent will be sent over.
|
|
|
|
stateUpdates chan interface{}
|
|
|
|
|
2018-09-04 11:16:02 +03:00
|
|
|
// balanceUpdates is a channel where notifications about updates to the
|
|
|
|
// wallet's balance will be sent. This channel will be buffered to
|
|
|
|
// ensure we have at most one pending update of this type to handle at
|
|
|
|
// a given time.
|
|
|
|
balanceUpdates chan *balanceUpdate
|
|
|
|
|
2018-08-31 09:55:41 +03:00
|
|
|
// nodeUpdates is a channel that changes to the graph node landscape
|
|
|
|
// will be sent over. This channel will be buffered to ensure we have
|
|
|
|
// at most one pending update of this type to handle at a given time.
|
|
|
|
nodeUpdates chan *nodeUpdates
|
|
|
|
|
2018-08-31 15:55:07 +03:00
|
|
|
// pendingOpenUpdates is a channel where updates about channel pending
|
|
|
|
// opening will be sent. This channel will be buffered to ensure we
|
|
|
|
// have at most one pending update of this type to handle at a given
|
|
|
|
// time.
|
|
|
|
pendingOpenUpdates chan *chanPendingOpenUpdate
|
|
|
|
|
2018-08-31 15:45:00 +03:00
|
|
|
// chanOpenFailures is a channel where updates about channel open
|
|
|
|
// failures will be sent. This channel will be buffered to ensure we
|
|
|
|
// have at most one pending update of this type to handle at a given
|
|
|
|
// time.
|
|
|
|
chanOpenFailures chan *chanOpenFailureUpdate
|
|
|
|
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
// totalBalance is the total number of satoshis the backing wallet is
|
|
|
|
// known to control at any given instance. This value will be updated
|
|
|
|
// when the agent receives external balance update signals.
|
|
|
|
totalBalance btcutil.Amount
|
|
|
|
|
2018-11-23 01:18:09 +03:00
|
|
|
// failedNodes lists nodes that we've previously attempted to initiate
|
|
|
|
// channels with, but didn't succeed.
|
|
|
|
failedNodes map[NodeID]struct{}
|
|
|
|
|
|
|
|
// pendingConns tracks the nodes that we are attempting to make
|
|
|
|
// connections to. This prevents us from making duplicate connection
|
|
|
|
// requests to the same node.
|
|
|
|
pendingConns map[NodeID]struct{}
|
|
|
|
|
|
|
|
// pendingOpens tracks the channels that we've requested to be
|
|
|
|
// initiated, but haven't yet been confirmed as being fully opened.
|
|
|
|
// This state is required as otherwise, we may go over our allotted
|
|
|
|
// channel limit, or open multiple channels to the same node.
|
|
|
|
pendingOpens map[NodeID]Channel
|
|
|
|
pendingMtx sync.Mutex
|
|
|
|
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
quit chan struct{}
|
|
|
|
wg sync.WaitGroup
|
|
|
|
}
|
|
|
|
|
|
|
|
// New creates a new instance of the Agent instantiated using the passed
|
|
|
|
// configuration and initial channel state. The initial channel state slice
|
|
|
|
// should be populated with the set of Channels that are currently opened by
|
|
|
|
// the backing Lightning Node.
|
|
|
|
func New(cfg Config, initialState []Channel) (*Agent, error) {
|
|
|
|
a := &Agent{
|
2018-08-31 15:55:07 +03:00
|
|
|
cfg: cfg,
|
|
|
|
chanState: make(map[lnwire.ShortChannelID]Channel),
|
|
|
|
quit: make(chan struct{}),
|
|
|
|
stateUpdates: make(chan interface{}),
|
2018-09-04 11:16:02 +03:00
|
|
|
balanceUpdates: make(chan *balanceUpdate, 1),
|
2018-08-31 15:55:07 +03:00
|
|
|
nodeUpdates: make(chan *nodeUpdates, 1),
|
|
|
|
chanOpenFailures: make(chan *chanOpenFailureUpdate, 1),
|
|
|
|
pendingOpenUpdates: make(chan *chanPendingOpenUpdate, 1),
|
2018-11-23 01:18:09 +03:00
|
|
|
failedNodes: make(map[NodeID]struct{}),
|
|
|
|
pendingConns: make(map[NodeID]struct{}),
|
|
|
|
pendingOpens: make(map[NodeID]Channel),
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range initialState {
|
|
|
|
a.chanState[c.ChanID] = c
|
|
|
|
}
|
|
|
|
|
|
|
|
return a, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start starts the agent along with any goroutines it needs to perform its
|
|
|
|
// normal duties.
|
|
|
|
func (a *Agent) Start() error {
|
|
|
|
if !atomic.CompareAndSwapUint32(&a.started, 0, 1) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-11-23 01:18:09 +03:00
|
|
|
rand.Seed(time.Now().Unix())
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
log.Infof("Autopilot Agent starting")
|
|
|
|
|
|
|
|
a.wg.Add(1)
|
2018-08-29 05:17:14 +03:00
|
|
|
go a.controller()
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop signals the Agent to gracefully shutdown. This function will block
|
|
|
|
// until all goroutines have exited.
|
|
|
|
func (a *Agent) Stop() error {
|
|
|
|
if !atomic.CompareAndSwapUint32(&a.stopped, 0, 1) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Infof("Autopilot Agent stopping")
|
|
|
|
|
|
|
|
close(a.quit)
|
|
|
|
a.wg.Wait()
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// balanceUpdate is a type of external state update that reflects an
|
|
|
|
// increase/decrease in the funds currently available to the wallet.
|
|
|
|
type balanceUpdate struct {
|
|
|
|
}
|
|
|
|
|
2018-08-24 04:52:49 +03:00
|
|
|
// nodeUpdates is a type of external state update that reflects an addition or
|
|
|
|
// modification in channel graph node membership.
|
|
|
|
type nodeUpdates struct{}
|
|
|
|
|
2018-08-07 04:18:05 +03:00
|
|
|
// chanOpenUpdate is a type of external state update that indicates a new
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
// channel has been opened, either by the Agent itself (within the main
|
|
|
|
// controller loop), or by an external user to the system.
|
|
|
|
type chanOpenUpdate struct {
|
|
|
|
newChan Channel
|
|
|
|
}
|
|
|
|
|
2018-08-07 04:18:05 +03:00
|
|
|
// chanPendingOpenUpdate is a type of external state update that indicates a new
|
|
|
|
// channel has been opened, either by the agent itself or an external subsystem,
|
|
|
|
// but is still pending.
|
|
|
|
type chanPendingOpenUpdate struct{}
|
|
|
|
|
2017-12-05 07:56:40 +03:00
|
|
|
// chanOpenFailureUpdate is a type of external state update that indicates
|
|
|
|
// a previous channel open failed, and that it might be possible to try again.
|
|
|
|
type chanOpenFailureUpdate struct{}
|
|
|
|
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
// chanCloseUpdate is a type of external state update that indicates that the
|
|
|
|
// backing Lightning Node has closed a previously open channel.
|
|
|
|
type chanCloseUpdate struct {
|
|
|
|
closedChans []lnwire.ShortChannelID
|
|
|
|
}
|
|
|
|
|
2018-09-04 11:16:02 +03:00
|
|
|
// OnBalanceChange is a callback that should be executed each time the balance
|
|
|
|
// of the backing wallet changes.
|
2018-08-29 05:17:14 +03:00
|
|
|
func (a *Agent) OnBalanceChange() {
|
2018-09-04 11:16:02 +03:00
|
|
|
select {
|
|
|
|
case a.balanceUpdates <- &balanceUpdate{}:
|
|
|
|
default:
|
|
|
|
}
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
}
|
|
|
|
|
2018-08-24 04:52:49 +03:00
|
|
|
// OnNodeUpdates is a callback that should be executed each time our channel
|
|
|
|
// graph has new nodes or their node announcements are updated.
|
|
|
|
func (a *Agent) OnNodeUpdates() {
|
2018-08-31 09:55:41 +03:00
|
|
|
select {
|
|
|
|
case a.nodeUpdates <- &nodeUpdates{}:
|
|
|
|
default:
|
|
|
|
}
|
2018-08-24 04:52:49 +03:00
|
|
|
}
|
|
|
|
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
// OnChannelOpen is a callback that should be executed each time a new channel
|
|
|
|
// is manually opened by the user or any system outside the autopilot agent.
|
|
|
|
func (a *Agent) OnChannelOpen(c Channel) {
|
2018-08-07 04:14:53 +03:00
|
|
|
a.wg.Add(1)
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
go func() {
|
2018-08-07 04:14:53 +03:00
|
|
|
defer a.wg.Done()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case a.stateUpdates <- &chanOpenUpdate{newChan: c}:
|
|
|
|
case <-a.quit:
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2018-08-07 04:18:05 +03:00
|
|
|
// OnChannelPendingOpen is a callback that should be executed each time a new
|
|
|
|
// channel is opened, either by the agent or an external subsystems, but is
|
|
|
|
// still pending.
|
|
|
|
func (a *Agent) OnChannelPendingOpen() {
|
2018-08-31 15:55:07 +03:00
|
|
|
select {
|
|
|
|
case a.pendingOpenUpdates <- &chanPendingOpenUpdate{}:
|
|
|
|
default:
|
|
|
|
}
|
2018-08-07 04:18:05 +03:00
|
|
|
}
|
|
|
|
|
2017-12-05 07:56:40 +03:00
|
|
|
// OnChannelOpenFailure is a callback that should be executed when the
|
|
|
|
// autopilot has attempted to open a channel, but failed. In this case we can
|
|
|
|
// retry channel creation with a different node.
|
|
|
|
func (a *Agent) OnChannelOpenFailure() {
|
2018-08-31 15:45:00 +03:00
|
|
|
select {
|
|
|
|
case a.chanOpenFailures <- &chanOpenFailureUpdate{}:
|
|
|
|
default:
|
|
|
|
}
|
2017-12-05 07:56:40 +03:00
|
|
|
}
|
|
|
|
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
// OnChannelClose is a callback that should be executed each time a prior
|
|
|
|
// channel has been closed for any reason. This includes regular
|
|
|
|
// closes, force closes, and channel breaches.
|
|
|
|
func (a *Agent) OnChannelClose(closedChans ...lnwire.ShortChannelID) {
|
2018-08-07 04:14:53 +03:00
|
|
|
a.wg.Add(1)
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
go func() {
|
2018-08-07 04:14:53 +03:00
|
|
|
defer a.wg.Done()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case a.stateUpdates <- &chanCloseUpdate{closedChans: closedChans}:
|
|
|
|
case <-a.quit:
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2017-08-16 04:23:52 +03:00
|
|
|
// mergeNodeMaps merges the Agent's set of nodes that it already has active
|
2018-08-31 06:33:57 +03:00
|
|
|
// channels open to, with the other sets of nodes that should be removed from
|
|
|
|
// consideration during heuristic selection. This ensures that the Agent doesn't
|
|
|
|
// attempt to open any "duplicate" channels to the same node.
|
|
|
|
func mergeNodeMaps(c map[NodeID]Channel,
|
|
|
|
skips ...map[NodeID]struct{}) map[NodeID]struct{} {
|
|
|
|
|
|
|
|
numNodes := len(c)
|
|
|
|
for _, skip := range skips {
|
|
|
|
numNodes += len(skip)
|
2018-01-13 13:01:55 +03:00
|
|
|
}
|
2018-08-31 06:33:57 +03:00
|
|
|
|
|
|
|
res := make(map[NodeID]struct{}, len(c)+numNodes)
|
2018-01-13 13:01:55 +03:00
|
|
|
for nodeID := range c {
|
|
|
|
res[nodeID] = struct{}{}
|
2017-08-16 04:23:52 +03:00
|
|
|
}
|
2018-08-31 06:33:57 +03:00
|
|
|
for _, skip := range skips {
|
|
|
|
for nodeID := range skip {
|
|
|
|
res[nodeID] = struct{}{}
|
|
|
|
}
|
|
|
|
}
|
2017-08-16 04:23:52 +03:00
|
|
|
|
2018-01-13 13:01:55 +03:00
|
|
|
return res
|
2017-08-16 04:23:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// mergeChanState merges the Agent's set of active channels, with the set of
|
|
|
|
// channels awaiting confirmation. This ensures that the agent doesn't go over
|
|
|
|
// the prescribed channel limit or fund allocation limit.
|
|
|
|
func mergeChanState(pendingChans map[NodeID]Channel,
|
|
|
|
activeChans channelState) []Channel {
|
|
|
|
|
|
|
|
numChans := len(pendingChans) + len(activeChans)
|
|
|
|
totalChans := make([]Channel, 0, numChans)
|
|
|
|
|
|
|
|
for _, activeChan := range activeChans.Channels() {
|
|
|
|
totalChans = append(totalChans, activeChan)
|
|
|
|
}
|
|
|
|
for _, pendingChan := range pendingChans {
|
|
|
|
totalChans = append(totalChans, pendingChan)
|
|
|
|
}
|
|
|
|
|
|
|
|
return totalChans
|
|
|
|
}
|
|
|
|
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
// controller implements the closed-loop control system of the Agent. The
|
|
|
|
// controller will make a decision w.r.t channel placement within the graph
|
2018-02-07 06:13:07 +03:00
|
|
|
// based on: its current internal state of the set of active channels open,
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
// and external state changes as a result of decisions it makes w.r.t channel
|
|
|
|
// allocation, or attributes affecting its control loop being updated by the
|
|
|
|
// backing Lightning Node.
|
2018-08-29 05:17:14 +03:00
|
|
|
func (a *Agent) controller() {
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
defer a.wg.Done()
|
|
|
|
|
|
|
|
// We'll start off by assigning our starting balance, and injecting
|
|
|
|
// that amount as an initial wake up to the main controller goroutine.
|
2018-08-29 05:17:14 +03:00
|
|
|
a.OnBalanceChange()
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
|
|
|
|
// TODO(roasbeef): do we in fact need to maintain order?
|
|
|
|
// * use sync.Cond if so
|
2018-03-11 03:47:29 +03:00
|
|
|
updateBalance := func() {
|
|
|
|
newBalance, err := a.cfg.WalletBalance()
|
|
|
|
if err != nil {
|
|
|
|
log.Warnf("unable to update wallet balance: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
a.totalBalance = newBalance
|
|
|
|
}
|
|
|
|
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
// TODO(roasbeef): add 10-minute wake up timer
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
// A new external signal has arrived. We'll use this to update
|
|
|
|
// our internal state, then determine if we should trigger a
|
|
|
|
// channel state modification (open/close, splice in/out).
|
|
|
|
case signal := <-a.stateUpdates:
|
|
|
|
log.Infof("Processing new external signal")
|
|
|
|
|
|
|
|
switch update := signal.(type) {
|
|
|
|
// A new channel has been opened successfully. This was
|
|
|
|
// either opened by the Agent, or an external system
|
|
|
|
// that is able to drive the Lightning Node.
|
|
|
|
case *chanOpenUpdate:
|
|
|
|
log.Debugf("New channel successfully opened, "+
|
|
|
|
"updating state with: %v",
|
|
|
|
spew.Sdump(update.newChan))
|
|
|
|
|
|
|
|
newChan := update.newChan
|
2018-12-19 16:54:55 +03:00
|
|
|
a.chanStateMtx.Lock()
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
a.chanState[newChan.ChanID] = newChan
|
2018-12-19 16:54:55 +03:00
|
|
|
a.chanStateMtx.Unlock()
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
|
2018-11-23 01:18:09 +03:00
|
|
|
a.pendingMtx.Lock()
|
|
|
|
delete(a.pendingOpens, newChan.Node)
|
|
|
|
a.pendingMtx.Unlock()
|
2017-08-16 04:23:52 +03:00
|
|
|
|
2018-03-11 03:47:29 +03:00
|
|
|
updateBalance()
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
// A channel has been closed, this may free up an
|
|
|
|
// available slot, triggering a new channel update.
|
|
|
|
case *chanCloseUpdate:
|
|
|
|
log.Debugf("Applying closed channel "+
|
|
|
|
"updates: %v",
|
|
|
|
spew.Sdump(update.closedChans))
|
|
|
|
|
2018-12-19 16:54:55 +03:00
|
|
|
a.chanStateMtx.Lock()
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
for _, closedChan := range update.closedChans {
|
|
|
|
delete(a.chanState, closedChan)
|
|
|
|
}
|
2018-12-19 16:54:55 +03:00
|
|
|
a.chanStateMtx.Unlock()
|
2018-03-11 03:47:29 +03:00
|
|
|
|
|
|
|
updateBalance()
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
}
|
|
|
|
|
2018-08-31 15:55:07 +03:00
|
|
|
// A new channel has been opened by the agent or an external
|
|
|
|
// subsystem, but is still pending confirmation.
|
|
|
|
case <-a.pendingOpenUpdates:
|
|
|
|
updateBalance()
|
|
|
|
|
2018-09-04 11:16:02 +03:00
|
|
|
// The balance of the backing wallet has changed, if more funds
|
|
|
|
// are now available, we may attempt to open up an additional
|
|
|
|
// channel, or splice in funds to an existing one.
|
|
|
|
case <-a.balanceUpdates:
|
|
|
|
log.Debug("Applying external balance state update")
|
|
|
|
|
|
|
|
updateBalance()
|
|
|
|
|
2018-08-31 15:45:00 +03:00
|
|
|
// The channel we tried to open previously failed for whatever
|
|
|
|
// reason.
|
|
|
|
case <-a.chanOpenFailures:
|
|
|
|
log.Debug("Retrying after previous channel open " +
|
|
|
|
"failure.")
|
|
|
|
|
|
|
|
updateBalance()
|
|
|
|
|
2018-08-31 09:55:41 +03:00
|
|
|
// New nodes have been added to the graph or their node
|
|
|
|
// announcements have been updated. We will consider opening
|
|
|
|
// channels to these nodes if we haven't stabilized.
|
|
|
|
case <-a.nodeUpdates:
|
|
|
|
log.Infof("Node updates received, assessing " +
|
|
|
|
"need for more channels")
|
|
|
|
|
2018-08-31 09:52:47 +03:00
|
|
|
// The agent has been signalled to exit, so we'll bail out
|
|
|
|
// immediately.
|
|
|
|
case <-a.quit:
|
|
|
|
return
|
|
|
|
}
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
|
2018-11-23 01:18:09 +03:00
|
|
|
a.pendingMtx.Lock()
|
|
|
|
log.Debugf("Pending channels: %v", spew.Sdump(a.pendingOpens))
|
|
|
|
a.pendingMtx.Unlock()
|
2018-08-31 09:52:47 +03:00
|
|
|
|
|
|
|
// With all the updates applied, we'll obtain a set of the
|
|
|
|
// current active channels (confirmed channels), and also
|
|
|
|
// factor in our set of unconfirmed channels.
|
2018-12-19 16:54:55 +03:00
|
|
|
a.chanStateMtx.Lock()
|
2018-11-23 01:18:09 +03:00
|
|
|
a.pendingMtx.Lock()
|
2018-12-19 16:54:55 +03:00
|
|
|
totalChans := mergeChanState(a.pendingOpens, a.chanState)
|
2018-11-23 01:18:09 +03:00
|
|
|
a.pendingMtx.Unlock()
|
2018-12-19 16:54:55 +03:00
|
|
|
a.chanStateMtx.Unlock()
|
2018-08-31 09:52:47 +03:00
|
|
|
|
|
|
|
// Now that we've updated our internal state, we'll consult our
|
2018-12-19 16:54:53 +03:00
|
|
|
// channel attachment heuristic to determine if we can open
|
|
|
|
// up any additional channels while staying within our
|
|
|
|
// constraints.
|
|
|
|
availableFunds, numChans := a.cfg.Constraints.ChannelBudget(
|
2018-08-31 09:52:47 +03:00
|
|
|
totalChans, a.totalBalance,
|
|
|
|
)
|
2018-12-19 16:54:53 +03:00
|
|
|
switch {
|
|
|
|
case numChans == 0:
|
|
|
|
continue
|
|
|
|
|
|
|
|
// If the amount is too small, we don't want to attempt opening
|
|
|
|
// another channel.
|
|
|
|
case availableFunds == 0:
|
|
|
|
continue
|
|
|
|
case availableFunds < a.cfg.Constraints.MinChanSize():
|
2018-08-31 09:52:47 +03:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Infof("Triggering attachment directive dispatch, "+
|
|
|
|
"total_funds=%v", a.totalBalance)
|
|
|
|
|
2018-11-23 01:18:09 +03:00
|
|
|
err := a.openChans(availableFunds, numChans, totalChans)
|
2018-08-31 09:52:47 +03:00
|
|
|
if err != nil {
|
2018-11-23 01:18:09 +03:00
|
|
|
log.Errorf("Unable to open channels: %v", err)
|
2018-08-31 09:52:47 +03:00
|
|
|
}
|
2018-11-23 01:18:09 +03:00
|
|
|
}
|
|
|
|
}
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
|
2018-11-23 01:18:09 +03:00
|
|
|
// openChans queries the agent's heuristic for a set of channel candidates, and
|
|
|
|
// attempts to open channels to them.
|
|
|
|
func (a *Agent) openChans(availableFunds btcutil.Amount, numChans uint32,
|
|
|
|
totalChans []Channel) error {
|
|
|
|
|
|
|
|
// We're to attempt an attachment so we'll obtain the set of
|
|
|
|
// nodes that we currently have channels with so we avoid
|
|
|
|
// duplicate edges.
|
2018-12-19 16:54:55 +03:00
|
|
|
a.chanStateMtx.Lock()
|
2018-11-23 01:18:09 +03:00
|
|
|
connectedNodes := a.chanState.ConnectedNodes()
|
2018-12-19 16:54:55 +03:00
|
|
|
a.chanStateMtx.Unlock()
|
|
|
|
|
2018-11-23 01:18:09 +03:00
|
|
|
a.pendingMtx.Lock()
|
|
|
|
nodesToSkip := mergeNodeMaps(a.pendingOpens,
|
|
|
|
a.pendingConns, connectedNodes, a.failedNodes,
|
|
|
|
)
|
|
|
|
a.pendingMtx.Unlock()
|
|
|
|
|
2018-11-23 01:18:09 +03:00
|
|
|
// Gather the set of all nodes in the graph, except those we
|
|
|
|
// want to skip.
|
|
|
|
selfPubBytes := a.cfg.Self.SerializeCompressed()
|
|
|
|
nodes := make(map[NodeID]struct{})
|
2018-12-19 16:54:54 +03:00
|
|
|
addresses := make(map[NodeID][]net.Addr)
|
2018-11-23 01:18:09 +03:00
|
|
|
if err := a.cfg.Graph.ForEachNode(func(node Node) error {
|
|
|
|
nID := NodeID(node.PubKey())
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2018-12-19 16:54:54 +03:00
|
|
|
// If the node has no known addresses, we cannot connect to it,
|
|
|
|
// so we'll skip it.
|
|
|
|
addrs := node.Addrs()
|
|
|
|
if len(addrs) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
addresses[nID] = addrs
|
|
|
|
|
2018-11-23 01:18:09 +03:00
|
|
|
// Additionally, if this node is in the blacklist, then
|
|
|
|
// we'll skip it.
|
|
|
|
if _, ok := nodesToSkip[nID]; ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
nodes[nID] = struct{}{}
|
|
|
|
return nil
|
|
|
|
}); err != nil {
|
|
|
|
return fmt.Errorf("unable to get graph nodes: %v", err)
|
|
|
|
}
|
|
|
|
|
2018-12-19 16:54:53 +03:00
|
|
|
// As channel size we'll use the maximum channel size available.
|
|
|
|
chanSize := a.cfg.Constraints.MaxChanSize()
|
|
|
|
if availableFunds-chanSize < 0 {
|
|
|
|
chanSize = availableFunds
|
|
|
|
}
|
|
|
|
|
2018-11-23 01:18:09 +03:00
|
|
|
// Use the heuristic to calculate a score for each node in the
|
|
|
|
// graph.
|
|
|
|
scores, err := a.cfg.Heuristic.NodeScores(
|
2018-12-19 16:54:53 +03:00
|
|
|
a.cfg.Graph, totalChans, chanSize, nodes,
|
2018-11-23 01:18:09 +03:00
|
|
|
)
|
|
|
|
if err != nil {
|
2018-11-23 01:18:09 +03:00
|
|
|
return fmt.Errorf("unable to calculate node scores : %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Debugf("Got scores for %d nodes", len(scores))
|
|
|
|
|
2018-12-19 17:22:33 +03:00
|
|
|
// Now use the score to make a weighted choice which nodes to attempt
|
|
|
|
// to open channels to.
|
2018-12-19 17:24:17 +03:00
|
|
|
scores, err = chooseN(numChans, scores)
|
2018-11-23 01:18:09 +03:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Unable to make weighted choice: %v",
|
|
|
|
err)
|
2018-11-23 01:18:09 +03:00
|
|
|
}
|
2018-08-31 09:52:47 +03:00
|
|
|
|
2018-12-19 17:22:33 +03:00
|
|
|
chanCandidates := make(map[NodeID]*AttachmentDirective)
|
2018-12-19 17:24:17 +03:00
|
|
|
for nID := range scores {
|
2018-12-19 17:22:33 +03:00
|
|
|
// Add addresses to the candidates.
|
|
|
|
addrs := addresses[nID]
|
|
|
|
|
|
|
|
// If the node has no known addresses, we cannot connect to it,
|
|
|
|
// so we'll skip it.
|
|
|
|
if len(addrs) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
chanCandidates[nID] = &AttachmentDirective{
|
|
|
|
NodeID: nID,
|
|
|
|
ChanAmt: chanSize,
|
|
|
|
Addrs: addrs,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-23 01:18:09 +03:00
|
|
|
if len(chanCandidates) == 0 {
|
|
|
|
log.Infof("No eligible candidates to connect to")
|
|
|
|
return nil
|
|
|
|
}
|
2018-08-31 09:52:47 +03:00
|
|
|
|
2018-11-23 01:18:09 +03:00
|
|
|
log.Infof("Attempting to execute channel attachment "+
|
|
|
|
"directives: %v", spew.Sdump(chanCandidates))
|
|
|
|
|
|
|
|
// Before proceeding, check to see if we have any slots
|
|
|
|
// available to open channels. If there are any, we will attempt
|
|
|
|
// to dispatch the retrieved directives since we can't be
|
|
|
|
// certain which ones may actually succeed. If too many
|
|
|
|
// connections succeed, we will they will be ignored and made
|
|
|
|
// available to future heuristic selections.
|
|
|
|
a.pendingMtx.Lock()
|
|
|
|
defer a.pendingMtx.Unlock()
|
2018-12-19 16:54:53 +03:00
|
|
|
if uint16(len(a.pendingOpens)) >= a.cfg.Constraints.MaxPendingOpens() {
|
2018-11-23 01:18:09 +03:00
|
|
|
log.Debugf("Reached cap of %v pending "+
|
|
|
|
"channel opens, will retry "+
|
|
|
|
"after success/failure",
|
2018-12-19 16:54:53 +03:00
|
|
|
a.cfg.Constraints.MaxPendingOpens())
|
2018-11-23 01:18:09 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// For each recommended attachment directive, we'll launch a
|
|
|
|
// new goroutine to attempt to carry out the directive. If any
|
|
|
|
// of these succeed, then we'll receive a new state update,
|
|
|
|
// taking us back to the top of our controller loop.
|
|
|
|
for _, chanCandidate := range chanCandidates {
|
|
|
|
// Skip candidates which we are already trying
|
|
|
|
// to establish a connection with.
|
|
|
|
nodeID := chanCandidate.NodeID
|
|
|
|
if _, ok := a.pendingConns[nodeID]; ok {
|
2018-08-31 06:33:57 +03:00
|
|
|
continue
|
|
|
|
}
|
2018-11-23 01:18:09 +03:00
|
|
|
a.pendingConns[nodeID] = struct{}{}
|
2018-08-31 06:33:57 +03:00
|
|
|
|
2018-11-23 01:18:09 +03:00
|
|
|
a.wg.Add(1)
|
2018-11-23 01:18:09 +03:00
|
|
|
go a.executeDirective(*chanCandidate)
|
2018-12-06 15:03:10 +03:00
|
|
|
}
|
2018-11-23 01:18:09 +03:00
|
|
|
return nil
|
2018-12-06 15:03:10 +03:00
|
|
|
}
|
2018-08-31 09:52:47 +03:00
|
|
|
|
2018-12-06 15:03:10 +03:00
|
|
|
// executeDirective attempts to connect to the channel candidate specified by
|
|
|
|
// the given attachment directive, and open a channel of the given size.
|
|
|
|
//
|
|
|
|
// NOTE: MUST be run as a goroutine.
|
|
|
|
func (a *Agent) executeDirective(directive AttachmentDirective) {
|
|
|
|
defer a.wg.Done()
|
2018-08-07 04:58:36 +03:00
|
|
|
|
2018-12-06 15:03:10 +03:00
|
|
|
// We'll start out by attempting to connect to the peer in order to
|
|
|
|
// begin the funding workflow.
|
|
|
|
nodeID := directive.NodeID
|
2018-12-06 15:59:46 +03:00
|
|
|
pub, err := btcec.ParsePubKey(nodeID[:], btcec.S256())
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Unable to parse pubkey %x: %v", nodeID, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-28 14:16:34 +03:00
|
|
|
connected := make(chan bool)
|
|
|
|
errChan := make(chan error)
|
|
|
|
|
|
|
|
// To ensure a call to ConnectToPeer doesn't block the agent from
|
|
|
|
// shutting down, we'll launch it in a non-waitgrouped goroutine, that
|
|
|
|
// will signal when a result is returned.
|
|
|
|
// TODO(halseth): use DialContext to cancel on transport level.
|
|
|
|
go func() {
|
|
|
|
alreadyConnected, err := a.cfg.ConnectToPeer(
|
|
|
|
pub, directive.Addrs,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
select {
|
|
|
|
case errChan <- err:
|
|
|
|
case <-a.quit:
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
|
|
|
case connected <- alreadyConnected:
|
|
|
|
case <-a.quit:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
var alreadyConnected bool
|
|
|
|
select {
|
|
|
|
case alreadyConnected = <-connected:
|
|
|
|
case err = <-errChan:
|
|
|
|
case <-a.quit:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-12-06 15:03:10 +03:00
|
|
|
if err != nil {
|
|
|
|
log.Warnf("Unable to connect to %x: %v",
|
|
|
|
pub.SerializeCompressed(), err)
|
|
|
|
|
|
|
|
// Since we failed to connect to them, we'll mark them as
|
|
|
|
// failed so that we don't attempt to connect to them again.
|
|
|
|
a.pendingMtx.Lock()
|
|
|
|
delete(a.pendingConns, nodeID)
|
|
|
|
a.failedNodes[nodeID] = struct{}{}
|
|
|
|
a.pendingMtx.Unlock()
|
2018-08-31 09:52:47 +03:00
|
|
|
|
2018-12-06 15:03:10 +03:00
|
|
|
// Finally, we'll trigger the agent to select new peers to
|
|
|
|
// connect to.
|
|
|
|
a.OnChannelOpenFailure()
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// The connection was successful, though before progressing we must
|
|
|
|
// check that we have not already met our quota for max pending open
|
|
|
|
// channels. This can happen if multiple directives were spawned but
|
|
|
|
// fewer slots were available, and other successful attempts finished
|
|
|
|
// first.
|
|
|
|
a.pendingMtx.Lock()
|
|
|
|
if uint16(len(a.pendingOpens)) >=
|
2018-12-19 16:54:53 +03:00
|
|
|
a.cfg.Constraints.MaxPendingOpens() {
|
2018-12-06 15:03:10 +03:00
|
|
|
// Since we've reached our max number of pending opens, we'll
|
|
|
|
// disconnect this peer and exit. However, if we were
|
|
|
|
// previously connected to them, then we'll make sure to
|
|
|
|
// maintain the connection alive.
|
|
|
|
if alreadyConnected {
|
|
|
|
// Since we succeeded in connecting, we won't add this
|
|
|
|
// peer to the failed nodes map, but we will remove it
|
|
|
|
// from a.pendingConns so that it can be retried in the
|
|
|
|
// future.
|
|
|
|
delete(a.pendingConns, nodeID)
|
|
|
|
a.pendingMtx.Unlock()
|
|
|
|
return
|
|
|
|
}
|
2018-08-07 04:18:05 +03:00
|
|
|
|
2018-12-06 15:03:10 +03:00
|
|
|
err = a.cfg.DisconnectPeer(pub)
|
|
|
|
if err != nil {
|
|
|
|
log.Warnf("Unable to disconnect peer %x: %v",
|
|
|
|
pub.SerializeCompressed(), err)
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
}
|
2018-12-06 15:03:10 +03:00
|
|
|
|
|
|
|
// Now that we have disconnected, we can remove this node from
|
|
|
|
// our pending conns map, permitting subsequent connection
|
|
|
|
// attempts.
|
|
|
|
delete(a.pendingConns, nodeID)
|
|
|
|
a.pendingMtx.Unlock()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we were successful, we'll track this peer in our set of pending
|
|
|
|
// opens. We do this here to ensure we don't stall on selecting new
|
|
|
|
// peers if the connection attempt happens to take too long.
|
|
|
|
delete(a.pendingConns, nodeID)
|
|
|
|
a.pendingOpens[nodeID] = Channel{
|
|
|
|
Capacity: directive.ChanAmt,
|
|
|
|
Node: nodeID,
|
|
|
|
}
|
|
|
|
a.pendingMtx.Unlock()
|
|
|
|
|
|
|
|
// We can then begin the funding workflow with this peer.
|
|
|
|
err = a.cfg.ChanController.OpenChannel(pub, directive.ChanAmt)
|
|
|
|
if err != nil {
|
|
|
|
log.Warnf("Unable to open channel to %x of %v: %v",
|
|
|
|
pub.SerializeCompressed(), directive.ChanAmt, err)
|
|
|
|
|
|
|
|
// As the attempt failed, we'll clear the peer from the set of
|
|
|
|
// pending opens and mark them as failed so we don't attempt to
|
|
|
|
// open a channel to them again.
|
|
|
|
a.pendingMtx.Lock()
|
|
|
|
delete(a.pendingOpens, nodeID)
|
|
|
|
a.failedNodes[nodeID] = struct{}{}
|
2018-11-23 01:18:09 +03:00
|
|
|
a.pendingMtx.Unlock()
|
2018-08-31 09:52:47 +03:00
|
|
|
|
2018-12-06 15:03:10 +03:00
|
|
|
// Trigger the agent to re-evaluate everything and possibly
|
|
|
|
// retry with a different node.
|
|
|
|
a.OnChannelOpenFailure()
|
|
|
|
|
|
|
|
// Finally, we should also disconnect the peer if we weren't
|
|
|
|
// already connected to them beforehand by an external
|
|
|
|
// subsystem.
|
|
|
|
if alreadyConnected {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err = a.cfg.DisconnectPeer(pub)
|
|
|
|
if err != nil {
|
|
|
|
log.Warnf("Unable to disconnect peer %x: %v",
|
|
|
|
pub.SerializeCompressed(), err)
|
|
|
|
}
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
}
|
2018-12-06 15:03:10 +03:00
|
|
|
|
|
|
|
// Since the channel open was successful and is currently pending,
|
|
|
|
// we'll trigger the autopilot agent to query for more peers.
|
|
|
|
a.OnChannelPendingOpen()
|
autopilot: "Look ma no hands!", introducing autopilot mode
This commit introduces the initial implementation of the autopilot
mode. Autopilot is new mode within lnd that enables automatic channel
management. This means that if enabled lnd will attempt to
automatically manage channels according to a set of heuristic defined
within the main configuration for autopilot.Agent instance.
The autopilot.Agent implements a simple closed control loop. It takes
in external signals such as wallet balance updates, new open channel,
and channels that are now closed the updates its internal state. With
each external trigger it will consult the registered
AttachmentHeuristic to decide: if it needs to open any more channels,
and if so how much it should use to open the channels, ultimately
returning a set of recommended AttachmentDirectives. The
autopilot.Agent loop will then take those attempt to establish
connection, and go back in waiting for a new external signal.
With this first implementation the default heuristic is the
ConstrainedPrefAttachment implementation of AttachmentHeuristic. Given
a min and max channel size, a limit on the number of channels, and the
percentage of wallet funds to allocate to channels, it will attempt to
execute a heuristic drive by the Barabási–Albert model model in order
to attempt to drive the global graph towards a scale free topology.
This is commit implements a foundational layer for future simulations,
optimization, and additional heuristics.
2017-08-11 07:14:41 +03:00
|
|
|
}
|
2018-12-19 16:54:55 +03:00
|
|
|
|
|
|
|
// HeuristicScores is an alias for a map that maps heuristic names to a map of
|
|
|
|
// scores for pubkeys.
|
|
|
|
type HeuristicScores map[string]map[NodeID]float64
|
|
|
|
|
|
|
|
// queryHeuristics gets node scores from all available simple heuristics, and
|
|
|
|
// the agent's current active heuristic.
|
|
|
|
func (a *Agent) queryHeuristics(nodes map[NodeID]struct{}) (
|
|
|
|
HeuristicScores, error) {
|
|
|
|
|
|
|
|
// Get the agent's current channel state.
|
|
|
|
a.chanStateMtx.Lock()
|
|
|
|
a.pendingMtx.Lock()
|
|
|
|
totalChans := mergeChanState(a.pendingOpens, a.chanState)
|
|
|
|
a.pendingMtx.Unlock()
|
|
|
|
a.chanStateMtx.Unlock()
|
|
|
|
|
|
|
|
// As channel size we'll use the maximum size.
|
|
|
|
chanSize := a.cfg.Constraints.MaxChanSize()
|
|
|
|
|
|
|
|
// We'll start by getting the scores from each available sub-heuristic,
|
|
|
|
// in addition the active agent heuristic.
|
|
|
|
report := make(HeuristicScores)
|
|
|
|
for _, h := range append(availableHeuristics, a.cfg.Heuristic) {
|
|
|
|
name := h.Name()
|
|
|
|
|
|
|
|
// If the active agent heuristic is among the simple heuristics
|
|
|
|
// it might get queried more than once. As an optimization
|
|
|
|
// we'll just skip it the second time.
|
|
|
|
if _, ok := report[name]; ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
s, err := h.NodeScores(
|
|
|
|
a.cfg.Graph, totalChans, chanSize, nodes,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("unable to get sub score: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Debugf("Heuristic \"%v\" scored %d nodes", name, len(s))
|
|
|
|
|
|
|
|
scores := make(map[NodeID]float64)
|
|
|
|
for nID, score := range s {
|
|
|
|
scores[nID] = score.Score
|
|
|
|
}
|
|
|
|
|
|
|
|
report[name] = scores
|
|
|
|
}
|
|
|
|
|
|
|
|
return report, nil
|
|
|
|
}
|