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  }