pilot.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. package lnd
  2. import (
  3. "errors"
  4. "fmt"
  5. "net"
  6. "github.com/btcsuite/btcd/btcec/v2"
  7. "github.com/btcsuite/btcd/btcutil"
  8. "github.com/btcsuite/btcd/wire"
  9. "github.com/lightningnetwork/lnd/autopilot"
  10. "github.com/lightningnetwork/lnd/chainreg"
  11. "github.com/lightningnetwork/lnd/funding"
  12. "github.com/lightningnetwork/lnd/lncfg"
  13. "github.com/lightningnetwork/lnd/lnwallet"
  14. "github.com/lightningnetwork/lnd/lnwire"
  15. "github.com/lightningnetwork/lnd/tor"
  16. )
  17. // validateAtplCfg is a helper method that makes sure the passed
  18. // configuration is sane. Currently it checks that the heuristic configuration
  19. // makes sense. In case the config is valid, it will return a list of
  20. // WeightedHeuristics that can be combined for use with the autopilot agent.
  21. func validateAtplCfg(cfg *lncfg.AutoPilot) ([]*autopilot.WeightedHeuristic,
  22. error) {
  23. var (
  24. heuristicsStr string
  25. sum float64
  26. heuristics []*autopilot.WeightedHeuristic
  27. )
  28. // Create a help text that we can return in case the config is not
  29. // correct.
  30. for _, a := range autopilot.AvailableHeuristics {
  31. heuristicsStr += fmt.Sprintf(" '%v' ", a.Name())
  32. }
  33. availStr := fmt.Sprintf("Available heuristics are: [%v]", heuristicsStr)
  34. // We'll go through the config and make sure all the heuristics exists,
  35. // and that the sum of their weights is 1.0.
  36. for name, weight := range cfg.Heuristic {
  37. a, ok := autopilot.AvailableHeuristics[name]
  38. if !ok {
  39. // No heuristic matching this config option was found.
  40. return nil, fmt.Errorf("heuristic %v not available. %v",
  41. name, availStr)
  42. }
  43. // If this heuristic was among the registered ones, we add it
  44. // to the list we'll give to the agent, and keep track of the
  45. // sum of weights.
  46. heuristics = append(
  47. heuristics,
  48. &autopilot.WeightedHeuristic{
  49. Weight: weight,
  50. AttachmentHeuristic: a,
  51. },
  52. )
  53. sum += weight
  54. }
  55. // Check found heuristics. We must have at least one to operate.
  56. if len(heuristics) == 0 {
  57. return nil, fmt.Errorf("no active heuristics: %v", availStr)
  58. }
  59. if sum != 1.0 {
  60. return nil, fmt.Errorf("heuristic weights must sum to 1.0")
  61. }
  62. return heuristics, nil
  63. }
  64. // chanController is an implementation of the autopilot.ChannelController
  65. // interface that's backed by a running lnd instance.
  66. type chanController struct {
  67. server *server
  68. private bool
  69. minConfs int32
  70. confTarget uint32
  71. chanMinHtlcIn lnwire.MilliSatoshi
  72. netParams chainreg.BitcoinNetParams
  73. }
  74. // OpenChannel opens a channel to a target peer, with a capacity of the
  75. // specified amount. This function should un-block immediately after the
  76. // funding transaction that marks the channel open has been broadcast.
  77. func (c *chanController) OpenChannel(target *btcec.PublicKey,
  78. amt btcutil.Amount) error {
  79. // With the connection established, we'll now establish our connection
  80. // to the target peer, waiting for the first update before we exit.
  81. feePerKw, err := c.server.cc.FeeEstimator.EstimateFeePerKW(
  82. c.confTarget,
  83. )
  84. if err != nil {
  85. return err
  86. }
  87. // Construct the open channel request and send it to the server to begin
  88. // the funding workflow.
  89. req := &funding.InitFundingMsg{
  90. TargetPubkey: target,
  91. ChainHash: *c.netParams.GenesisHash,
  92. SubtractFees: true,
  93. LocalFundingAmt: amt,
  94. PushAmt: 0,
  95. MinHtlcIn: c.chanMinHtlcIn,
  96. FundingFeePerKw: feePerKw,
  97. Private: c.private,
  98. RemoteCsvDelay: 0,
  99. MinConfs: c.minConfs,
  100. MaxValueInFlight: 0,
  101. }
  102. updateStream, errChan := c.server.OpenChannel(req)
  103. select {
  104. case err := <-errChan:
  105. return err
  106. case <-updateStream:
  107. return nil
  108. case <-c.server.quit:
  109. return nil
  110. }
  111. }
  112. func (c *chanController) CloseChannel(chanPoint *wire.OutPoint) error {
  113. return nil
  114. }
  115. // A compile time assertion to ensure chanController meets the
  116. // autopilot.ChannelController interface.
  117. var _ autopilot.ChannelController = (*chanController)(nil)
  118. // initAutoPilot initializes a new autopilot.ManagerCfg to manage an autopilot.
  119. // Agent instance based on the passed configuration structs. The agent and all
  120. // interfaces needed to drive it won't be launched before the Manager's
  121. // StartAgent method is called.
  122. func initAutoPilot(svr *server, cfg *lncfg.AutoPilot,
  123. minHTLCIn lnwire.MilliSatoshi, netParams chainreg.BitcoinNetParams) (
  124. *autopilot.ManagerCfg, error) {
  125. atplLog.Infof("Instantiating autopilot with active=%v, "+
  126. "max_channels=%d, allocation=%f, min_chan_size=%d, "+
  127. "max_chan_size=%d, private=%t, min_confs=%d, conf_target=%d",
  128. cfg.Active, cfg.MaxChannels, cfg.Allocation, cfg.MinChannelSize,
  129. cfg.MaxChannelSize, cfg.Private, cfg.MinConfs, cfg.ConfTarget)
  130. // Set up the constraints the autopilot heuristics must adhere to.
  131. atplConstraints := autopilot.NewConstraints(
  132. btcutil.Amount(cfg.MinChannelSize),
  133. btcutil.Amount(cfg.MaxChannelSize),
  134. uint16(cfg.MaxChannels),
  135. 10,
  136. cfg.Allocation,
  137. )
  138. heuristics, err := validateAtplCfg(cfg)
  139. if err != nil {
  140. return nil, err
  141. }
  142. weightedAttachment, err := autopilot.NewWeightedCombAttachment(
  143. heuristics...,
  144. )
  145. if err != nil {
  146. return nil, err
  147. }
  148. // With the heuristic itself created, we can now populate the remainder
  149. // of the items that the autopilot agent needs to perform its duties.
  150. self := svr.identityECDH.PubKey()
  151. pilotCfg := autopilot.Config{
  152. Self: self,
  153. Heuristic: weightedAttachment,
  154. ChanController: &chanController{
  155. server: svr,
  156. private: cfg.Private,
  157. minConfs: cfg.MinConfs,
  158. confTarget: cfg.ConfTarget,
  159. chanMinHtlcIn: minHTLCIn,
  160. netParams: netParams,
  161. },
  162. WalletBalance: func() (btcutil.Amount, error) {
  163. return svr.cc.Wallet.ConfirmedBalance(
  164. cfg.MinConfs, lnwallet.DefaultAccountName,
  165. )
  166. },
  167. Graph: autopilot.ChannelGraphFromDatabase(svr.graphDB),
  168. Constraints: atplConstraints,
  169. ConnectToPeer: func(target *btcec.PublicKey, addrs []net.Addr) (bool, error) {
  170. // First, we'll check if we're already connected to the
  171. // target peer. If we are, we can exit early. Otherwise,
  172. // we'll need to establish a connection.
  173. if _, err := svr.FindPeer(target); err == nil {
  174. return true, nil
  175. }
  176. // We can't establish a channel if no addresses were
  177. // provided for the peer.
  178. if len(addrs) == 0 {
  179. return false, errors.New("no addresses specified")
  180. }
  181. atplLog.Tracef("Attempting to connect to %x",
  182. target.SerializeCompressed())
  183. lnAddr := &lnwire.NetAddress{
  184. IdentityKey: target,
  185. ChainNet: netParams.Net,
  186. }
  187. // We'll attempt to successively connect to each of the
  188. // advertised IP addresses until we've either exhausted
  189. // the advertised IP addresses, or have made a
  190. // connection.
  191. var connected bool
  192. for _, addr := range addrs {
  193. switch addr.(type) {
  194. case *net.TCPAddr, *tor.OnionAddr:
  195. lnAddr.Address = addr
  196. default:
  197. return false, fmt.Errorf("unknown "+
  198. "address type %T", addr)
  199. }
  200. err := svr.ConnectToPeer(
  201. lnAddr, false, svr.cfg.ConnectionTimeout,
  202. )
  203. if err != nil {
  204. // If we weren't able to connect to the
  205. // peer at this address, then we'll move
  206. // onto the next.
  207. continue
  208. }
  209. connected = true
  210. break
  211. }
  212. // If we weren't able to establish a connection at all,
  213. // then we'll error out.
  214. if !connected {
  215. return false, errors.New("exhausted all " +
  216. "advertised addresses")
  217. }
  218. return false, nil
  219. },
  220. DisconnectPeer: svr.DisconnectPeer,
  221. }
  222. // Create and return the autopilot.ManagerCfg that administrates this
  223. // agent-pilot instance.
  224. return &autopilot.ManagerCfg{
  225. Self: self,
  226. PilotCfg: &pilotCfg,
  227. ChannelState: func() ([]autopilot.LocalChannel, error) {
  228. // We'll fetch the current state of open
  229. // channels from the database to use as initial
  230. // state for the auto-pilot agent.
  231. activeChannels, err := svr.chanStateDB.FetchAllChannels()
  232. if err != nil {
  233. return nil, err
  234. }
  235. chanState := make([]autopilot.LocalChannel,
  236. len(activeChannels))
  237. for i, channel := range activeChannels {
  238. localCommit := channel.LocalCommitment
  239. balance := localCommit.LocalBalance.ToSatoshis()
  240. chanState[i] = autopilot.LocalChannel{
  241. ChanID: channel.ShortChanID(),
  242. Balance: balance,
  243. Node: autopilot.NewNodeID(
  244. channel.IdentityPub,
  245. ),
  246. }
  247. }
  248. return chanState, nil
  249. },
  250. ChannelInfo: func(chanPoint wire.OutPoint) (
  251. *autopilot.LocalChannel, error) {
  252. channel, err := svr.chanStateDB.FetchChannel(nil, chanPoint)
  253. if err != nil {
  254. return nil, err
  255. }
  256. localCommit := channel.LocalCommitment
  257. return &autopilot.LocalChannel{
  258. ChanID: channel.ShortChanID(),
  259. Balance: localCommit.LocalBalance.ToSatoshis(),
  260. Node: autopilot.NewNodeID(channel.IdentityPub),
  261. }, nil
  262. },
  263. SubscribeTransactions: svr.cc.Wallet.SubscribeTransactions,
  264. SubscribeTopology: svr.chanRouter.SubscribeTopology,
  265. }, nil
  266. }