bitcoind_common.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. //go:build bitcoind
  2. // +build bitcoind
  3. package lntest
  4. import (
  5. "errors"
  6. "fmt"
  7. "os"
  8. "os/exec"
  9. "path/filepath"
  10. "time"
  11. "github.com/btcsuite/btcd/chaincfg"
  12. "github.com/btcsuite/btcd/rpcclient"
  13. "github.com/lightningnetwork/lnd/lntest/node"
  14. "github.com/lightningnetwork/lnd/lntest/port"
  15. )
  16. // logDirPattern is the pattern of the name of the temporary log directory.
  17. const logDirPattern = "%s/.backendlogs"
  18. // BitcoindBackendConfig is an implementation of the BackendConfig interface
  19. // backed by a Bitcoind node.
  20. type BitcoindBackendConfig struct {
  21. rpcHost string
  22. rpcUser string
  23. rpcPass string
  24. zmqBlockPath string
  25. zmqTxPath string
  26. p2pPort int
  27. rpcClient *rpcclient.Client
  28. rpcPolling bool
  29. // minerAddr is the p2p address of the miner to connect to.
  30. minerAddr string
  31. }
  32. // A compile time assertion to ensure BitcoindBackendConfig meets the
  33. // BackendConfig interface.
  34. var _ node.BackendConfig = (*BitcoindBackendConfig)(nil)
  35. // GenArgs returns the arguments needed to be passed to LND at startup for
  36. // using this node as a chain backend.
  37. func (b BitcoindBackendConfig) GenArgs() []string {
  38. var args []string
  39. args = append(args, "--bitcoin.node=bitcoind")
  40. args = append(args, fmt.Sprintf("--bitcoind.rpchost=%v", b.rpcHost))
  41. args = append(args, fmt.Sprintf("--bitcoind.rpcuser=%v", b.rpcUser))
  42. args = append(args, fmt.Sprintf("--bitcoind.rpcpass=%v", b.rpcPass))
  43. if b.rpcPolling {
  44. args = append(args, fmt.Sprintf("--bitcoind.rpcpolling"))
  45. args = append(args,
  46. fmt.Sprintf("--bitcoind.blockpollinginterval=10ms"))
  47. args = append(args,
  48. fmt.Sprintf("--bitcoind.txpollinginterval=10ms"))
  49. } else {
  50. args = append(args, fmt.Sprintf("--bitcoind.zmqpubrawblock=%v",
  51. b.zmqBlockPath))
  52. args = append(args, fmt.Sprintf("--bitcoind.zmqpubrawtx=%v",
  53. b.zmqTxPath))
  54. }
  55. return args
  56. }
  57. // ConnectMiner is called to establish a connection to the test miner.
  58. func (b BitcoindBackendConfig) ConnectMiner() error {
  59. return b.rpcClient.AddNode(b.minerAddr, rpcclient.ANAdd)
  60. }
  61. // DisconnectMiner is called to disconnect the miner.
  62. func (b BitcoindBackendConfig) DisconnectMiner() error {
  63. return b.rpcClient.AddNode(b.minerAddr, rpcclient.ANRemove)
  64. }
  65. // Credentials returns the rpc username, password and host for the backend.
  66. func (b BitcoindBackendConfig) Credentials() (string, string, string, error) {
  67. return b.rpcUser, b.rpcPass, b.rpcHost, nil
  68. }
  69. // Name returns the name of the backend type.
  70. func (b BitcoindBackendConfig) Name() string {
  71. return "bitcoind"
  72. }
  73. // newBackend starts a bitcoind node with the given extra parameters and returns
  74. // a BitcoindBackendConfig for that node.
  75. func newBackend(miner string, netParams *chaincfg.Params, extraArgs []string,
  76. rpcPolling bool) (*BitcoindBackendConfig, func() error, error) {
  77. baseLogDir := fmt.Sprintf(logDirPattern, node.GetLogDir())
  78. if netParams != &chaincfg.RegressionNetParams {
  79. return nil, nil, fmt.Errorf("only regtest supported")
  80. }
  81. if err := os.MkdirAll(baseLogDir, 0700); err != nil {
  82. return nil, nil, err
  83. }
  84. logFile, err := filepath.Abs(baseLogDir + "/bitcoind.log")
  85. if err != nil {
  86. return nil, nil, err
  87. }
  88. tempBitcoindDir, err := os.MkdirTemp("", "bitcoind")
  89. if err != nil {
  90. return nil, nil,
  91. fmt.Errorf("unable to create temp directory: %w", err)
  92. }
  93. zmqBlockAddr := fmt.Sprintf("tcp://127.0.0.1:%d",
  94. port.NextAvailablePort())
  95. zmqTxAddr := fmt.Sprintf("tcp://127.0.0.1:%d", port.NextAvailablePort())
  96. rpcPort := port.NextAvailablePort()
  97. p2pPort := port.NextAvailablePort()
  98. cmdArgs := []string{
  99. "-datadir=" + tempBitcoindDir,
  100. "-whitelist=127.0.0.1", // whitelist localhost to speed up relay
  101. "-rpcauth=weks:469e9bb14ab2360f8e226efed5ca6f" +
  102. "d$507c670e800a95284294edb5773b05544b" +
  103. "220110063096c221be9933c82d38e1",
  104. fmt.Sprintf("-rpcport=%d", rpcPort),
  105. fmt.Sprintf("-port=%d", p2pPort),
  106. "-zmqpubrawblock=" + zmqBlockAddr,
  107. "-zmqpubrawtx=" + zmqTxAddr,
  108. "-debuglogfile=" + logFile,
  109. }
  110. cmdArgs = append(cmdArgs, extraArgs...)
  111. bitcoind := exec.Command("bitcoind", cmdArgs...)
  112. err = bitcoind.Start()
  113. if err != nil {
  114. if err := os.RemoveAll(tempBitcoindDir); err != nil {
  115. fmt.Printf("unable to remote temp dir %v: %v",
  116. tempBitcoindDir, err)
  117. }
  118. return nil, nil, fmt.Errorf("couldn't start bitcoind: %w", err)
  119. }
  120. cleanUp := func() error {
  121. _ = bitcoind.Process.Kill()
  122. _ = bitcoind.Wait()
  123. var errStr string
  124. // After shutting down the chain backend, we'll make a copy of
  125. // the log file before deleting the temporary log dir.
  126. logDestination := fmt.Sprintf(
  127. "%s/output_bitcoind_chainbackend.log", node.GetLogDir(),
  128. )
  129. err := node.CopyFile(logDestination, logFile)
  130. if err != nil {
  131. errStr += fmt.Sprintf("unable to copy file: %v\n", err)
  132. }
  133. if err = os.RemoveAll(baseLogDir); err != nil {
  134. errStr += fmt.Sprintf(
  135. "cannot remove dir %s: %v\n", baseLogDir, err,
  136. )
  137. }
  138. if err := os.RemoveAll(tempBitcoindDir); err != nil {
  139. errStr += fmt.Sprintf(
  140. "cannot remove dir %s: %v\n",
  141. tempBitcoindDir, err,
  142. )
  143. }
  144. if errStr != "" {
  145. return errors.New(errStr)
  146. }
  147. return nil
  148. }
  149. // Allow process to start.
  150. time.Sleep(1 * time.Second)
  151. rpcHost := fmt.Sprintf("127.0.0.1:%d", rpcPort)
  152. rpcUser := "weks"
  153. rpcPass := "weks"
  154. rpcCfg := rpcclient.ConnConfig{
  155. Host: rpcHost,
  156. User: rpcUser,
  157. Pass: rpcPass,
  158. DisableConnectOnNew: true,
  159. DisableAutoReconnect: false,
  160. DisableTLS: true,
  161. HTTPPostMode: true,
  162. }
  163. client, err := rpcclient.New(&rpcCfg, nil)
  164. if err != nil {
  165. _ = cleanUp()
  166. return nil, nil, fmt.Errorf("unable to create rpc client: %w",
  167. err)
  168. }
  169. bd := BitcoindBackendConfig{
  170. rpcHost: rpcHost,
  171. rpcUser: rpcUser,
  172. rpcPass: rpcPass,
  173. zmqBlockPath: zmqBlockAddr,
  174. zmqTxPath: zmqTxAddr,
  175. p2pPort: p2pPort,
  176. rpcClient: client,
  177. minerAddr: miner,
  178. rpcPolling: rpcPolling,
  179. }
  180. return &bd, cleanUp, nil
  181. }