config.go
  1  // Copyright (c) 2013-2016 The btcsuite developers
  2  // Use of this source code is governed by an ISC
  3  // license that can be found in the LICENSE file.
  4  
  5  package main
  6  
  7  import (
  8  	"fmt"
  9  	"os"
 10  	"path/filepath"
 11  
 12  	"github.com/btcsuite/btcd/chaincfg"
 13  	"github.com/btcsuite/btcd/database"
 14  	_ "github.com/btcsuite/btcd/database/ffldb"
 15  	"github.com/btcsuite/btcd/wire"
 16  	"github.com/btcsuite/btcutil"
 17  	flags "github.com/jessevdk/go-flags"
 18  )
 19  
 20  const (
 21  	minCandidates        = 1
 22  	maxCandidates        = 20
 23  	defaultNumCandidates = 5
 24  	defaultDbType        = "ffldb"
 25  )
 26  
 27  var (
 28  	btcdHomeDir     = btcutil.AppDataDir("btcd", false)
 29  	defaultDataDir  = filepath.Join(btcdHomeDir, "data")
 30  	knownDbTypes    = database.SupportedDrivers()
 31  	activeNetParams = &chaincfg.MainNetParams
 32  )
 33  
 34  // config defines the configuration options for findcheckpoint.
 35  //
 36  // See loadConfig for details on the configuration load process.
 37  type config struct {
 38  	DataDir        string `short:"b" long:"datadir" description:"Location of the btcd data directory"`
 39  	DbType         string `long:"dbtype" description:"Database backend to use for the Block Chain"`
 40  	TestNet3       bool   `long:"testnet" description:"Use the test network"`
 41  	RegressionTest bool   `long:"regtest" description:"Use the regression test network"`
 42  	SimNet         bool   `long:"simnet" description:"Use the simulation test network"`
 43  	NumCandidates  int    `short:"n" long:"numcandidates" description:"Max num of checkpoint candidates to show {1-20}"`
 44  	UseGoOutput    bool   `short:"g" long:"gooutput" description:"Display the candidates using Go syntax that is ready to insert into the btcchain checkpoint list"`
 45  }
 46  
 47  // validDbType returns whether or not dbType is a supported database type.
 48  func validDbType(dbType string) bool {
 49  	for _, knownType := range knownDbTypes {
 50  		if dbType == knownType {
 51  			return true
 52  		}
 53  	}
 54  
 55  	return false
 56  }
 57  
 58  // netName returns the name used when referring to a bitcoin network.  At the
 59  // time of writing, btcd currently places blocks for testnet version 3 in the
 60  // data and log directory "testnet", which does not match the Name field of the
 61  // chaincfg parameters.  This function can be used to override this directory name
 62  // as "testnet" when the passed active network matches wire.TestNet3.
 63  //
 64  // A proper upgrade to move the data and log directories for this network to
 65  // "testnet3" is planned for the future, at which point this function can be
 66  // removed and the network parameter's name used instead.
 67  func netName(chainParams *chaincfg.Params) string {
 68  	switch chainParams.Net {
 69  	case wire.TestNet3:
 70  		return "testnet"
 71  	default:
 72  		return chainParams.Name
 73  	}
 74  }
 75  
 76  // loadConfig initializes and parses the config using command line options.
 77  func loadConfig() (*config, []string, error) {
 78  	// Default config.
 79  	cfg := config{
 80  		DataDir:       defaultDataDir,
 81  		DbType:        defaultDbType,
 82  		NumCandidates: defaultNumCandidates,
 83  	}
 84  
 85  	// Parse command line options.
 86  	parser := flags.NewParser(&cfg, flags.Default)
 87  	remainingArgs, err := parser.Parse()
 88  	if err != nil {
 89  		if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp {
 90  			parser.WriteHelp(os.Stderr)
 91  		}
 92  		return nil, nil, err
 93  	}
 94  
 95  	// Multiple networks can't be selected simultaneously.
 96  	funcName := "loadConfig"
 97  	numNets := 0
 98  	// Count number of network flags passed; assign active network params
 99  	// while we're at it
100  	if cfg.TestNet3 {
101  		numNets++
102  		activeNetParams = &chaincfg.TestNet3Params
103  	}
104  	if cfg.RegressionTest {
105  		numNets++
106  		activeNetParams = &chaincfg.RegressionNetParams
107  	}
108  	if cfg.SimNet {
109  		numNets++
110  		activeNetParams = &chaincfg.SimNetParams
111  	}
112  	if numNets > 1 {
113  		str := "%s: The testnet, regtest, and simnet params can't be " +
114  			"used together -- choose one of the three"
115  		err := fmt.Errorf(str, funcName)
116  		fmt.Fprintln(os.Stderr, err)
117  		parser.WriteHelp(os.Stderr)
118  		return nil, nil, err
119  	}
120  
121  	// Validate database type.
122  	if !validDbType(cfg.DbType) {
123  		str := "%s: The specified database type [%v] is invalid -- " +
124  			"supported types %v"
125  		err := fmt.Errorf(str, "loadConfig", cfg.DbType, knownDbTypes)
126  		fmt.Fprintln(os.Stderr, err)
127  		parser.WriteHelp(os.Stderr)
128  		return nil, nil, err
129  	}
130  
131  	// Append the network type to the data directory so it is "namespaced"
132  	// per network.  In addition to the block database, there are other
133  	// pieces of data that are saved to disk such as address manager state.
134  	// All data is specific to a network, so namespacing the data directory
135  	// means each individual piece of serialized data does not have to
136  	// worry about changing names per network and such.
137  	cfg.DataDir = filepath.Join(cfg.DataDir, netName(activeNetParams))
138  
139  	// Validate the number of candidates.
140  	if cfg.NumCandidates < minCandidates || cfg.NumCandidates > maxCandidates {
141  		str := "%s: The specified number of candidates is out of " +
142  			"range -- parsed [%v]"
143  		err = fmt.Errorf(str, "loadConfig", cfg.NumCandidates)
144  		fmt.Fprintln(os.Stderr, err)
145  		parser.WriteHelp(os.Stderr)
146  		return nil, nil, err
147  	}
148  
149  	return &cfg, remainingArgs, nil
150  }