harness_node_manager.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. package lntest
  2. import (
  3. "context"
  4. "fmt"
  5. "sync"
  6. "sync/atomic"
  7. "testing"
  8. "github.com/lightningnetwork/lnd/lnrpc"
  9. "github.com/lightningnetwork/lnd/lntest/node"
  10. "github.com/lightningnetwork/lnd/lntest/wait"
  11. )
  12. // nodeManager is responsible for handling the start and stop of a given node.
  13. // It also keeps track of the running nodes.
  14. type nodeManager struct {
  15. sync.Mutex
  16. // chainBackend houses the information necessary to use a node as LND
  17. // chain backend, such as rpc configuration, P2P information etc.
  18. chainBackend node.BackendConfig
  19. // currentTestCase holds the name for the currently run test case.
  20. currentTestCase string
  21. // lndBinary is the full path to the lnd binary that was specifically
  22. // compiled with all required itest flags.
  23. lndBinary string
  24. // dbBackend sets the database backend to use.
  25. dbBackend node.DatabaseBackend
  26. // nativeSQL sets the database backend to use native SQL when
  27. // applicable.
  28. nativeSQL bool
  29. // activeNodes is a map of all running nodes, format:
  30. // {pubkey: *HarnessNode}.
  31. activeNodes map[uint32]*node.HarnessNode
  32. // standbyNodes is a map of all the standby nodes, format:
  33. // {pubkey: *HarnessNode}.
  34. standbyNodes map[uint32]*node.HarnessNode
  35. // nodeCounter is a monotonically increasing counter that's used as the
  36. // node's unique ID.
  37. nodeCounter uint32
  38. // feeServiceURL is the url of the fee service.
  39. feeServiceURL string
  40. }
  41. // newNodeManager creates a new node manager instance.
  42. func newNodeManager(lndBinary string, dbBackend node.DatabaseBackend,
  43. nativeSQL bool) *nodeManager {
  44. return &nodeManager{
  45. lndBinary: lndBinary,
  46. dbBackend: dbBackend,
  47. nativeSQL: nativeSQL,
  48. activeNodes: make(map[uint32]*node.HarnessNode),
  49. standbyNodes: make(map[uint32]*node.HarnessNode),
  50. }
  51. }
  52. // nextNodeID generates a unique sequence to be used as the node's ID.
  53. func (nm *nodeManager) nextNodeID() uint32 {
  54. nodeID := atomic.AddUint32(&nm.nodeCounter, 1)
  55. return nodeID - 1
  56. }
  57. // newNode initializes a new HarnessNode, supporting the ability to initialize
  58. // a wallet with or without a seed. If useSeed is false, the returned harness
  59. // node can be used immediately. Otherwise, the node will require an additional
  60. // initialization phase where the wallet is either created or restored.
  61. func (nm *nodeManager) newNode(t *testing.T, name string, extraArgs []string,
  62. password []byte, noAuth bool) (*node.HarnessNode, error) {
  63. cfg := &node.BaseNodeConfig{
  64. Name: name,
  65. LogFilenamePrefix: nm.currentTestCase,
  66. Password: password,
  67. BackendCfg: nm.chainBackend,
  68. ExtraArgs: extraArgs,
  69. FeeURL: nm.feeServiceURL,
  70. DBBackend: nm.dbBackend,
  71. NativeSQL: nm.nativeSQL,
  72. NodeID: nm.nextNodeID(),
  73. LndBinary: nm.lndBinary,
  74. NetParams: harnessNetParams,
  75. SkipUnlock: noAuth,
  76. }
  77. node, err := node.NewHarnessNode(t, cfg)
  78. if err != nil {
  79. return nil, err
  80. }
  81. // Put node in activeNodes to ensure Shutdown is called even if start
  82. // returns an error.
  83. nm.registerNode(node)
  84. return node, nil
  85. }
  86. // RegisterNode records a new HarnessNode in the NetworkHarnesses map of known
  87. // nodes. This method should only be called with nodes that have successfully
  88. // retrieved their public keys via FetchNodeInfo.
  89. func (nm *nodeManager) registerNode(node *node.HarnessNode) {
  90. nm.Lock()
  91. nm.activeNodes[node.Cfg.NodeID] = node
  92. nm.Unlock()
  93. }
  94. // ShutdownNode stops an active lnd process and returns when the process has
  95. // exited and any temporary directories have been cleaned up.
  96. func (nm *nodeManager) shutdownNode(node *node.HarnessNode) error {
  97. if err := node.Shutdown(); err != nil {
  98. return err
  99. }
  100. delete(nm.activeNodes, node.Cfg.NodeID)
  101. return nil
  102. }
  103. // restartNode attempts to restart a lightning node by shutting it down
  104. // cleanly, then restarting the process. This function is fully blocking. Upon
  105. // restart, the RPC connection to the node will be re-attempted, continuing iff
  106. // the connection attempt is successful. If the callback parameter is non-nil,
  107. // then the function will be executed after the node shuts down, but *before*
  108. // the process has been started up again.
  109. func (nm *nodeManager) restartNode(ctxt context.Context,
  110. hn *node.HarnessNode, callback func() error) error {
  111. // Stop the node.
  112. if err := hn.Stop(); err != nil {
  113. return fmt.Errorf("restart node got error: %w", err)
  114. }
  115. if callback != nil {
  116. if err := callback(); err != nil {
  117. return err
  118. }
  119. }
  120. // Start the node without unlocking the wallet.
  121. if hn.Cfg.SkipUnlock {
  122. return hn.StartWithNoAuth(ctxt)
  123. }
  124. return hn.Start(ctxt)
  125. }
  126. // unlockNode unlocks the node's wallet if the password is configured.
  127. // Additionally, each time the node is unlocked, the caller can pass a set of
  128. // SCBs to pass in via the Unlock method allowing them to restore channels
  129. // during restart.
  130. func (nm *nodeManager) unlockNode(hn *node.HarnessNode,
  131. chanBackups ...*lnrpc.ChanBackupSnapshot) error {
  132. // If the node doesn't have a password set, then we can exit here as we
  133. // don't need to unlock it.
  134. if len(hn.Cfg.Password) == 0 {
  135. return nil
  136. }
  137. // Otherwise, we'll unlock the wallet, then complete the final steps
  138. // for the node initialization process.
  139. unlockReq := &lnrpc.UnlockWalletRequest{
  140. WalletPassword: hn.Cfg.Password,
  141. }
  142. if len(chanBackups) != 0 {
  143. unlockReq.ChannelBackups = chanBackups[0]
  144. unlockReq.RecoveryWindow = 100
  145. }
  146. err := wait.NoError(func() error {
  147. return hn.Unlock(unlockReq)
  148. }, DefaultTimeout)
  149. if err != nil {
  150. return fmt.Errorf("%s: failed to unlock: %w", hn.Name(), err)
  151. }
  152. return nil
  153. }
  154. // initWalletAndNode will unlock the node's wallet and finish setting up the
  155. // node so it's ready to take RPC requests.
  156. func (nm *nodeManager) initWalletAndNode(hn *node.HarnessNode,
  157. req *lnrpc.InitWalletRequest) ([]byte, error) {
  158. // Pass the init request via rpc to finish unlocking the node.
  159. resp := hn.RPC.InitWallet(req)
  160. // Now that the wallet is unlocked, before creating an authed
  161. // connection we will close the old unauthed connection.
  162. if err := hn.CloseConn(); err != nil {
  163. return nil, fmt.Errorf("close unauthed conn failed")
  164. }
  165. // Init the node, which will create the authed grpc conn and all its
  166. // rpc clients.
  167. err := hn.InitNode(resp.AdminMacaroon)
  168. // In stateless initialization mode we get a macaroon back that we have
  169. // to return to the test, otherwise gRPC calls won't be possible since
  170. // there are no macaroon files created in that mode.
  171. // In stateful init the admin macaroon will just be nil.
  172. return resp.AdminMacaroon, err
  173. }