github.com/decred/dcrlnd@v0.7.6/lntest/harness_miner.go (about) 1 package lntest 2 3 import ( 4 "context" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "strings" 10 "time" 11 12 "github.com/decred/dcrd/chaincfg/chainhash" 13 "github.com/decred/dcrd/chaincfg/v3" 14 "github.com/decred/dcrd/rpc/jsonrpc/types/v4" 15 "github.com/decred/dcrd/rpcclient/v8" 16 "github.com/decred/dcrlnd/internal/testutils" 17 rpctest "github.com/decred/dcrtest/dcrdtest" 18 ) 19 20 const ( 21 // minerLogFilename is the default log filename for the miner node. 22 minerLogFilename = "output_btcd_miner.log" 23 24 // minerLogDir is the default log dir for the miner node. 25 minerLogDir = ".minerlogs" 26 ) 27 28 var harnessNetParams = chaincfg.SimNetParams() 29 30 type HarnessMiner struct { 31 *rpctest.Harness 32 33 // Client adapts decred's dcrdtest.Harness interface to lnd's. 34 Client *rpcclient.Client 35 36 // voting wallet used in dcrlnd to keep the chain going. 37 votingWallet *rpctest.VotingWallet 38 votingWalletCancel func() 39 40 // runCtx is a context with cancel method. It's used to signal when the 41 // node needs to quit, and used as the parent context when spawning 42 runCtx context.Context 43 cancel context.CancelFunc 44 45 // logPath is the directory path of the miner's logs. 46 logPath string 47 48 // logFilename is the saved log filename of the miner node. 49 logFilename string 50 } 51 52 // NewMiner creates a new miner using dcrd backend with the default log file 53 // dir and name. 54 func NewMiner() (*HarnessMiner, error) { 55 return newMiner(minerLogDir, minerLogFilename) 56 } 57 58 // NewTempMiner creates a new miner using dcrd backend with the specified log 59 // file dir and name. 60 func NewTempMiner(tempDir, tempLogFilename string) (*HarnessMiner, error) { 61 return newMiner(tempDir, tempLogFilename) 62 } 63 64 // newMiner creates a new miner using btcd's rpctest. 65 func newMiner(minerDirName, logFilename string) (*HarnessMiner, error) { 66 handler := &rpcclient.NotificationHandlers{} 67 baseLogPath := fmt.Sprintf("%s/%s", GetLogDir(), minerDirName) 68 69 args := []string{ 70 "--rejectnonstd", 71 "--txindex", 72 "--nobanning", 73 "--debuglevel=debug", 74 "--logdir=" + baseLogPath, 75 "--maxorphantx=0", 76 "--rpcmaxclients=100", 77 "--rpcmaxwebsockets=100", 78 "--rpcmaxconcurrentreqs=100", 79 "--logsize=100M", 80 "--maxsameip=200", 81 } 82 83 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 84 defer cancel() 85 miner, err := testutils.NewSetupRPCTest(ctx, 5, harnessNetParams, handler, 86 args, false, 0) 87 if err != nil { 88 return nil, fmt.Errorf( 89 "unable to create mining node: %v", err, 90 ) 91 } 92 93 ctxt, cancel := context.WithCancel(context.Background()) 94 m := &HarnessMiner{ 95 Harness: miner, 96 Client: miner.Node, 97 runCtx: ctxt, 98 cancel: cancel, 99 logPath: baseLogPath, 100 logFilename: logFilename, 101 } 102 return m, nil 103 } 104 105 // Stop shuts down the miner and saves its logs. 106 func (h *HarnessMiner) Stop() error { 107 h.cancel() 108 109 if err := h.TearDown(); err != nil { 110 return fmt.Errorf("tear down miner got error: %s", err) 111 } 112 113 return h.saveLogs() 114 } 115 116 // saveLogs copies the node logs and save it to the file specified by 117 // h.logFilename. 118 func (h *HarnessMiner) saveLogs() error { 119 // After shutting down the miner, we'll make a copy of the log files 120 // before deleting the temporary log dir. 121 path := fmt.Sprintf("%s/%s", h.logPath, harnessNetParams.Name) 122 files, err := ioutil.ReadDir(path) 123 if err != nil { 124 return fmt.Errorf("unable to read log directory: %v", err) 125 } 126 127 for _, file := range files { 128 newFilename := strings.Replace( 129 file.Name(), "btcd.log", h.logFilename, 1, 130 ) 131 copyPath := fmt.Sprintf("%s/../%s", h.logPath, newFilename) 132 133 logFile := fmt.Sprintf("%s/%s", path, file.Name()) 134 err := CopyFile(filepath.Clean(copyPath), logFile) 135 if err != nil { 136 return fmt.Errorf("unable to copy file: %v", err) 137 } 138 } 139 140 if err = os.RemoveAll(h.logPath); err != nil { 141 return fmt.Errorf("cannot remove dir %s: %v", h.logPath, err) 142 } 143 144 return nil 145 } 146 147 // waitForTxInMempool blocks until the target txid is seen in the mempool. If 148 // the transaction isn't seen within the network before the passed timeout, 149 // then an error is returned. 150 func (h *HarnessMiner) waitForTxInMempool(txid chainhash.Hash) error { 151 ticker := time.NewTicker(50 * time.Millisecond) 152 defer ticker.Stop() 153 154 var mempool []*chainhash.Hash 155 for { 156 select { 157 case <-h.runCtx.Done(): 158 return fmt.Errorf("NetworkHarness has been torn down") 159 case <-time.After(DefaultTimeout): 160 return fmt.Errorf("wanted %v, found %v txs "+ 161 "in mempool: %v", txid, len(mempool), mempool) 162 163 case <-ticker.C: 164 var err error 165 mempool, err = h.Client.GetRawMempool(h.runCtx, types.GRMAll) 166 if err != nil { 167 return err 168 } 169 170 for _, mempoolTx := range mempool { 171 if *mempoolTx == txid { 172 return nil 173 } 174 } 175 } 176 } 177 }