config.go raw

   1  package podconfig
   2  
   3  import (
   4  	
   5  	// This ensures the database drivers get registered
   6  	// _ "github.com/p9c/p9/pkg/database/ffldb"
   7  )
   8  
   9  //
  10  // // Config defines the configuration options for pod. See loadConfig for details on the configuration load process.
  11  // type Config struct {
  12  // 	ShowVersion          *bool            `short:"True" long:"version" description:"Display version information and exit"`
  13  // 	ConfigFile           *string          `short:"C" long:"configfile" description:"Path to configuration file"`
  14  // 	DataDir              *string          `short:"b" long:"datadir" description:"Directory to store data"`
  15  // 	LogDir               *string          `long:"logdir" description:"Directory to log output."`
  16  // 	DebugLevel           *string          `long:"debuglevel" description:"baseline debug level for all subsystems unless specified"`
  17  // 	AddPeers             *cli.StringSlice `short:"a" long:"addpeer" description:"Add a peer to connect with at startup"`
  18  // 	ConnectPeers         *cli.StringSlice `long:"connect" description:"Connect only to the specified peers at startup"`
  19  // 	DisableListen        *bool            `long:"nolisten" description:"Disable listening for incoming connections -- NOTE: Listening is automatically disabled if the --connect or --proxy options are used without also specifying listen interfaces via --listen"`
  20  // 	P2PListeners            *cli.StringSlice `long:"listen" description:"Add an interface/port to listen for connections (default all interfaces port: 11047, testnet: 21047)"`
  21  // 	MaxPeers             *int             `long:"maxpeers" description:"Max number of inbound and outbound peers"`
  22  // 	DisableBanning       *bool            `long:"nobanning" description:"Disable banning of misbehaving peers"`
  23  // 	BanDuration          *time.Duration   `long:"banduration" description:"How long to ban misbehaving peers.  Valid time units are {s, m, h, d}.  Minimum 1 second"`
  24  // 	BanThreshold         *int             `long:"banthreshold" description:"Maximum allowed ban score before disconnecting and banning misbehaving peers."`
  25  // 	Whitelists           *cli.StringSlice `long:"whitelist" description:"Add an IP network or IP that will not be banned. (eg. 192.168.1.0/24 or ::1)"`
  26  // 	RPCUser              *string          `short:"u" long:"rpcuser" description:"Username for RPC connections"`
  27  // 	RPCPass              *string          `short:"P" long:"rpcpass" default-mask:"-" description:"Password for RPC connections"`
  28  // 	RPCLimitUser         *string          `long:"rpclimituser" description:"Username for limited RPC connections"`
  29  // 	RPCLimitPass         *string          `long:"rpclimitpass" default-mask:"-" description:"Password for limited RPC connections"`
  30  // 	RPCListeners         *cli.StringSlice `long:"rpclisten" description:"Add an interface/port to listen for RPC connections (default port: 11048, testnet: 21048) gives sha256d block templates"`
  31  // 	RPCCert              *string          `long:"rpccert" description:"File containing the certificate file"`
  32  // 	RPCKey               *string          `long:"rpckey" description:"File containing the certificate key"`
  33  // 	RPCMaxClients        *int             `long:"rpcmaxclients" description:"Max number of RPC clients for standard connections"`
  34  // 	RPCMaxWebsockets     *int             `long:"rpcmaxwebsockets" description:"Max number of RPC websocket connections"`
  35  // 	RPCMaxConcurrentReqs *int             `long:"rpcmaxconcurrentreqs" description:"Max number of concurrent RPC requests that may be processed concurrently"`
  36  // 	RPCQuirks            *bool            `long:"rpcquirks" description:"Mirror some JSON-RPC quirks of Bitcoin Core -- NOTE: Discouraged unless interoperability issues need to be worked around"`
  37  // 	DisableRPC           *bool            `long:"norpc" description:"Disable built-in RPC server -- NOTE: The RPC server is disabled by default if no rpcuser/rpcpass or rpclimituser/rpclimitpass is specified"`
  38  // 	TLS                  *bool            `long:"tls" description:"Enable TLS for the RPC server"`
  39  // 	DisableDNSSeed       *bool            `long:"nodnsseed" description:"Disable DNS seeding for peers"`
  40  // 	ExternalIPs          *cli.StringSlice `long:"externalip" description:"Add an ip to the list of local addresses we claim to listen on to peers"`
  41  // 	Proxy                *string          `long:"proxy" description:"Connect via SOCKS5 proxy (eg. 127.0.0.1:9050)"`
  42  // 	ProxyUser            *string          `long:"proxyuser" description:"Username for proxy server"`
  43  // 	ProxyPass            *string          `long:"proxypass" default-mask:"-" description:"Password for proxy server"`
  44  // 	OnionProxy           *string          `long:"onion" description:"Connect to tor hidden services via SOCKS5 proxy (eg. 127.0.0.1:9050)"`
  45  // 	OnionProxyUser       *string          `long:"onionuser" description:"Username for onion proxy server"`
  46  // 	OnionProxyPass       *string          `long:"onionpass" default-mask:"-" description:"Password for onion proxy server"`
  47  // 	Onion                *bool            `long:"noonion" description:"Disable connecting to tor hidden services"`
  48  // 	TorIsolation         *bool            `long:"torisolation" description:"Enable Tor stream isolation by randomizing user credentials for each connection."`
  49  // 	TestNet3             *bool            `long:"testnet" description:"Use the test network"`
  50  // 	RegressionTest       *bool            `long:"regtest" description:"Use the regression test network"`
  51  // 	SimNet               *bool            `long:"simnet" description:"Use the simulation test network"`
  52  // 	AddCheckpoints       *cli.StringSlice `long:"addcheckpoint" description:"Add a custom checkpoint.  Format: '<height>:<hash>'"`
  53  // 	DisableCheckpoints   *bool            `long:"nocheckpoints" description:"Disable built-in checkpoints.  Don't do this unless you know what you're doing."`
  54  // 	DbType               *string          `long:"dbtype" description:"Database backend to use for the Block Chain"`
  55  // 	Profile              *string          `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"`
  56  // 	CPUProfile           *string          `long:"cpuprofile" description:"Write CPU profile to the specified file"`
  57  // 	Upnp                 *bool            `long:"upnp" description:"Use UPnP to map our listening port outside of NAT"`
  58  // 	MinRelayTxFee        *float64         `long:"minrelaytxfee" description:"The minimum transaction fee in DUO/kB to be considered a non-zero fee."`
  59  // 	FreeTxRelayLimit     *float64         `long:"limitfreerelay" description:"Limit relay of transactions with no transaction fee to the given amount in thousands of bytes per minute"`
  60  // 	NoRelayPriority      *bool            `long:"norelaypriority" description:"Do not require free or low-fee transactions to have high priority for relaying"`
  61  // 	TrickleInterval      *time.Duration   `long:"trickleinterval" description:"Minimum time between attempts to send new inventory to a connected peer"`
  62  // 	MaxOrphanTxs         *int             `long:"maxorphantx" description:"Max number of orphan transactions to keep in memory"`
  63  // 	Algo                 *string          `long:"algo" description:"Sets the algorithm for the CPU miner ( blake14lr, cryptonight7v2, keccak, lyra2rev2, scrypt, sha256d, stribog, skein, x11 default is 'random')"`
  64  // 	Generate             *bool            `long:"generate" description:"Generate (mine) bitcoins using the CPU"`
  65  // 	GenThreads           *int             `long:"genthreads" description:"Number of CPU threads to use with CPU miner -1 = all cores"`
  66  // 	MiningAddrs          *cli.StringSlice `long:"miningaddrs" description:"Add the specified payment address to the list of addresses to use for generated blocks, at least one is required if generate or minerport are set"`
  67  // 	MinerListener        *string          `long:"minerlistener" description:"listen address for miner controller"`
  68  // 	MinerPass            *string          `long:"minerpass" description:"Encryption password required for miner clients to subscribe to work updates, for use over insecure connections"`
  69  // 	BlockMinSize         *int             `long:"blockminsize" description:"Mininum block size in bytes to be used when creating a block"`
  70  // 	BlockMaxSize         *int             `long:"blockmaxsize" description:"Maximum block size in bytes to be used when creating a block"`
  71  // 	BlockMinWeight       *int             `long:"blockminweight" description:"Mininum block weight to be used when creating a block"`
  72  // 	BlockMaxWeight       *int             `long:"blockmaxweight" description:"Maximum block weight to be used when creating a block"`
  73  // 	BlockPrioritySize    *int             `long:"blockprioritysize" description:"Size in bytes for high-priority/low-fee transactions when creating a block"`
  74  // 	UserAgentComments    *cli.StringSlice `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."`
  75  // 	NoPeerBloomFilters   *bool            `long:"nopeerbloomfilters" description:"Disable bloom filtering support"`
  76  // 	NoCFilters           *bool            `long:"nocfilters" description:"Disable committed filtering (CF) support"`
  77  // 	DropCfIndex          *bool            `long:"dropcfindex" description:"Deletes the index used for committed filtering (CF) support from the database on start up and then exits."`
  78  // 	SigCacheMaxSize      *int             `long:"sigcachemaxsize" description:"The maximum number of entries in the signature verification cache"`
  79  // 	BlocksOnly           *bool            `long:"blocksonly" description:"Do not accept transactions from remote peers."`
  80  // 	TxIndex              *bool            `long:"txindex" description:"Maintain a full hash-based transaction index which makes all transactions available via the getrawtransaction RPC"`
  81  // 	DropTxIndex          *bool            `long:"droptxindex" description:"Deletes the hash-based transaction index from the database on start up and then exits."`
  82  // 	AddrIndex            *bool            `long:"addrindex" description:"Maintain a full address-based transaction index which makes the searchrawtransactions RPC available"`
  83  // 	DropAddrIndex        *bool            `long:"dropaddrindex" description:"Deletes the address-based transaction index from the database on start up and then exits."`
  84  // 	RelayNonStd          *bool            `long:"relaynonstd" description:"Relay non-standard transactions regardless of the default settings for the active network."`
  85  // 	RejectNonStd         *bool            `long:"rejectnonstd" description:"Reject non-standard transactions regardless of the default settings for the active network."`
  86  // }
  87  
  88  // serviceOptions defines the configuration options for the daemon as a service on Windows.
  89  type serviceOptions struct {
  90  	ServiceCommand string `short:"s" long:"service" description:"Service command {install, remove, start, stop}"`
  91  }
  92  
  93  var (
  94  	// defaultHomeDir is the default home directory location (
  95  	// this should be centralised)
  96  	
  97  	// KnownDbTypes stores the currently supported database drivers
  98  	// KnownDbTypes = database.SupportedDrivers()
  99  	// runServiceCommand is only set to a real function on Windows.
 100  	// It is used to parse and execute service commands specified via the -s flag.
 101  	runServiceCommand func(string) error
 102  )
 103  
 104  // // newCheckpointFromStr parses checkpoints in the '<height>:<hash>' format.
 105  // func newCheckpointFromStr(checkpoint string) (chaincfg.Checkpoint, error) {
 106  // 	parts := strings.Split(checkpoint, ":")
 107  // 	if len(parts) != 2 {
 108  // 		return chaincfg.Checkpoint{}, fmt.Errorf(
 109  // 			"unable to parse "+
 110  // 				"checkpoint %q -- use the syntax <height>:<hash>",
 111  // 			checkpoint,
 112  // 		)
 113  // 	}
 114  // 	height, e := strconv.ParseInt(parts[0], 10, 32)
 115  // 	if e != nil {
 116  // 		return chaincfg.Checkpoint{}, fmt.Errorf(
 117  // 			"unable to parse "+
 118  // 				"checkpoint %q due to malformed height", checkpoint,
 119  // 		)
 120  // 	}
 121  // 	if len(parts[1]) == 0 {
 122  // 		return chaincfg.Checkpoint{}, fmt.Errorf(
 123  // 			"unable to parse "+
 124  // 				"checkpoint %q due to missing hash", checkpoint,
 125  // 		)
 126  // 	}
 127  // 	hash, e := chainhash.NewHashFromStr(parts[1])
 128  // 	if e != nil {
 129  // 		return chaincfg.Checkpoint{}, fmt.Errorf(
 130  // 			"unable to parse "+
 131  // 				"checkpoint %q due to malformed hash", checkpoint,
 132  // 		)
 133  // 	}
 134  // 	return chaincfg.Checkpoint{
 135  // 			Height: int32(height),
 136  // 			Hash:   hash,
 137  // 		},
 138  // 		nil
 139  // }
 140  
 141  //
 142  // // NewConfigParser returns a new command line flags parser.
 143  // func NewConfigParser(cfg *Config, so *serviceOptions, options flags.Options) *flags.Parser {
 144  // 	parser := flags.NewParser(cfg, options)
 145  // 	if runtime.GOOS == "windows" {
 146  // 		_, e := parser.AddGroup("Service Options", "Service Options", so)
 147  // 		if e != nil {
 148  // 			panic(e)
 149  // 		}
 150  // 	}
 151  // 	return parser
 152  // }
 153  
 154  // // ParseCheckpoints checks the checkpoint strings for valid syntax ( '<height>:<hash>') and parses them to
 155  // // chaincfg.Checkpoint instances.
 156  // func ParseCheckpoints(checkpointStrings []string) ([]chaincfg.Checkpoint, error) {
 157  // 	if len(checkpointStrings) == 0 {
 158  // 		return nil, nil
 159  // 	}
 160  // 	checkpoints := make([]chaincfg.Checkpoint, len(checkpointStrings))
 161  // 	for i, cpString := range checkpointStrings {
 162  // 		checkpoint, e := newCheckpointFromStr(cpString)
 163  // 		if e != nil {
 164  // 			return nil, e
 165  // 		}
 166  // 		checkpoints[i] = checkpoint
 167  // 	}
 168  // 	return checkpoints, nil
 169  // }
 170  //
 171  // // ValidDbType returns whether or not dbType is a supported database type.
 172  // func ValidDbType(dbType string) bool {
 173  // 	for _, knownType := range KnownDbTypes {
 174  // 		if dbType == knownType {
 175  // 			return true
 176  // 		}
 177  // 	}
 178  // 	return false
 179  // }
 180  //
 181  // // validLogLevel returns whether or not logLevel is a valid debug log level.
 182  // func validLogLevel(logLevel string) bool {
 183  // 	switch logLevel {
 184  // 	case "trace":
 185  // 		fallthrough
 186  // 	case "debug":
 187  // 		fallthrough
 188  // 	case "info":
 189  // 		fallthrough
 190  // 	case "warn":
 191  // 		fallthrough
 192  // 	case "error":
 193  // 		fallthrough
 194  // 	case "critical":
 195  // 		return true
 196  // 	}
 197  // 	return false
 198  // }
 199  
 200  // // createDefaultConfig copies the file sample-pod.
 201  // conf to the given destination path, and populates it with some randomly generated RPC username and password.
 202  // func createDefaultConfigFile(destinationPath string) (e error) {
 203  // 	// Create the destination directory if it does not exists
 204  // 	e := os.MkdirAll(filepath.Dir(destinationPath), 0700)
 205  // 	if e != nil  {
 206  //		DB// 		return e
 207  // 	}
 208  // 	// We generate a random user and password
 209  // 	randomBytes := make([]byte, 20)
 210  // 	_, e = rand.Read(randomBytes)
 211  // 	if e != nil  {
 212  //		DB// 		return e
 213  // 	}
 214  // 	generatedRPCUser := base64.StdEncoding.EncodeToString(randomBytes)
 215  // 	_, e = rand.Read(randomBytes)
 216  // 	if e != nil  {
 217  //		DB// 		return e
 218  // 	}
 219  // 	generatedRPCPass := base64.StdEncoding.EncodeToString(randomBytes)
 220  // 	var bb bytes.Buffer
 221  // 	bb.Write(samplePodConf)
 222  // 	dest, e := os.OpenFile(destinationPath,
 223  // 		os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
 224  // 	if e != nil  {
 225  //		DB// 		return e
 226  // 	}
 227  // 	defer dest.Close()
 228  // 	reader := bufio.NewReader(&bb)
 229  // 	for e != io.EOF {
 230  // 		var line string
 231  // 		line, e = reader.ReadString('\n')
 232  // 		if e != nil  && e != io.EOF {
 233  // 			return e
 234  // 		}
 235  // 		if strings.Contains(line, "rpcuser=") {
 236  // 			line = "rpcuser=" + generatedRPCUser + "\n"
 237  // 		} else if strings.Contains(line, "rpcpass=") {
 238  // 			line = "rpcpass=" + generatedRPCPass + "\n"
 239  // 		}
 240  // 		if _, e = dest.WriteString(line); E.Chk(e) {
 241  // 			return e
 242  // 		}
 243  // 	}
 244  // 	return nil
 245  // }
 246  
 247  /*
 248  // loadConfig initializes and parses the config using a config file and command line options.
 249  // The configuration proceeds as follows:
 250  // 	1) Start with a default config with sane settings
 251  // 	2) Pre-parse the command line to check for an alternative config file
 252  // 	3) Load configuration file overwriting defaults with any specified options
 253  // 	4) Parse CLI options and overwrite/add any specified options
 254  // The above results in pod functioning properly without any config settings while still allowing the user to override settings with config files and command line options.  Command line options always take precedence.
 255  func loadConfig() (
 256  	*Config, []string,
 257  	error,
 258  ) {
 259  	// Default config.
 260  	cfg := Config{
 261  		ConfigFile:           DefaultConfigFile,
 262  		MaxPeers:             DefaultMaxPeers,
 263  		BanDuration:          DefaultBanDuration,
 264  		BanThreshold:         DefaultBanThreshold,
 265  		RPCMaxClients:        DefaultMaxRPCClients,
 266  		RPCMaxWebsockets:     DefaultMaxRPCWebsockets,
 267  		RPCMaxConcurrentReqs: DefaultMaxRPCConcurrentReqs,
 268  		DataDir:              DefaultDataDir,
 269  		LogDir:               DefaultLogDir,
 270  		DbType:               DefaultDbType,
 271  		RPCKey:               DefaultRPCKeyFile,
 272  		RPCCert:              DefaultRPCCertFile,
 273  		MinRelayTxFee:        mempool.DefaultMinRelayTxFee.ToDUO(),
 274  		FreeTxRelayLimit:     DefaultFreeTxRelayLimit,
 275  		TrickleInterval:      DefaultTrickleInterval,
 276  		BlockMinSize:         DefaultBlockMinSize,
 277  		BlockMaxSize:         DefaultBlockMaxSize,
 278  		BlockMinWeight:       DefaultBlockMinWeight,
 279  		BlockMaxWeight:       DefaultBlockMaxWeight,
 280  		BlockPrioritySize:    mempool.DefaultBlockPrioritySize,
 281  		MaxOrphanTxs:         DefaultMaxOrphanTransactions,
 282  		SigCacheMaxSize:      DefaultSigCacheMaxSize,
 283  		Generate:             DefaultGenerate,
 284  		GenThreads:           1,
 285  		TxIndex:              DefaultTxIndex,
 286  		AddrIndex:            DefaultAddrIndex,
 287  		Algo:                 DefaultAlgo,
 288  	}
 289  	// Service options which are only added on Windows.
 290  	serviceOpts := serviceOptions{}
 291  	// Pre-parse the command line options to see if an alternative config file or the version flag was specified.  Any errors aside from the help message error can be ignored here since they will be caught by the final parse below.
 292  	preCfg := cfg
 293  	preParser := NewConfigParser(&preCfg, &serviceOpts, flags.HelpFlag)
 294  	_, e := preParser.Parse()
 295  	if e != nil  {
 296  		if e, ok := err.(*flags.DBError); ok && e.Type == flags.ErrHelp {
 297  			DB			return nil, nil, e
 298  		}
 299  	}
 300  	// Show the version and exit if the version flag was specified.
 301  	appName := filepath.Base(os.Args[0])
 302  	appName = strings.TrimSuffix(appName, filepath.Ext(appName))
 303  	usageMessage := fmt.Sprintf("Use %s -h to show usage", appName)
 304  	if preCfg.ShowVersion {
 305  		fmt.Println(appName, "version", Version())
 306  		os.Exit(0)
 307  	}
 308  	// Perform service command and exit if specified.  Invalid service commands show an appropriate error.  Only runs on Windows since the runServiceCommand function will be nil when not on Windows.
 309  	if serviceOpts.ServiceCommand != "" && runServiceCommand != nil {
 310  		e := runServiceCommand(serviceOpts.ServiceCommand)
 311  		if e != nil  {
 312  			fmt.Fprintln(os.Stderr, e)
 313  		}
 314  		os.Exit(0)
 315  	}
 316  	// Load additional config from file.
 317  	var configFileError error
 318  	parser := NewConfigParser(&cfg, &serviceOpts, flags.Default)
 319  	if !(preCfg.RegressionTest || preCfg.SimNet) || preCfg.ConfigFile !=
 320  		DefaultConfigFile {
 321  		if _, e = os.Stat(preCfg.ConfigFile); os.IsNotExist(e) {
 322  			e := createDefaultConfigFile(preCfg.ConfigFile)
 323  			if e != nil  {
 324  				fmt.Fprintf(os.Stderr, "DBError creating a "+
 325  					"default config file: %v\n", e)
 326  			}
 327  		}
 328  		e := flags.NewIniParser(parser).ParseFile(preCfg.ConfigFile)
 329  		if e != nil  {
 330  			if _, ok := err.(*os.PathError); !ok {
 331  				fmt.Fprintf(os.Stderr, "DBError parsing config "+
 332  					"file: %v\n", e)
 333  				fmt.Fprintln(os.Stderr, usageMessage)
 334  				return nil, nil, e
 335  			}
 336  			configFileError = err
 337  		}
 338  	}
 339  	// Don't add peers from the config file when in regression test mode.
 340  	if preCfg.RegressionTest && len(cfg.AddPeers) > 0 {
 341  		cfg.AddPeers = nil
 342  	}
 343  	// Parse command line options again to ensure they take precedence.
 344  	remainingArgs, e := parser.Parse()
 345  	if e != nil  {
 346  		if e, ok := err.(*flags.DBError); !ok || e.Type != flags.ErrHelp {
 347  			fmt.Fprintln(os.Stderr, usageMessage)
 348  		}
 349  		return nil, nil, e
 350  	}
 351  	// Create the home directory if it doesn't already exist.
 352  	funcName := "loadConfig"
 353  	e = os.MkdirAll(DefaultHomeDir, 0700)
 354  	if e != nil  {
 355  		// Show a nicer error message if it's because a symlink is linked to a directory that does not exist (probably because it's not mounted).
 356  		if e, ok := err.(*os.PathError); ok && os.IsExist(e) {
 357  			if link, lerr := os.Readlink(e.Path); lerr == nil {
 358  				str := "is symlink %s -> %s mounted?"
 359  				e = fmt.Errorf(str, e.Path, link)
 360  			}
 361  		}
 362  		str := "%s: Failed to create home directory: %v"
 363  		e := fmt.Errorf(str, funcName, e)
 364  		fmt.Fprintln(os.Stderr, e)
 365  		return nil, nil, e
 366  	}
 367  	// Multiple networks can't be selected simultaneously.
 368  	numNets := 0
 369  	// Count number of network flags passed; assign active network netparams while we're at it
 370  	if cfg.TestNet3 {
 371  		numNets++
 372  		ActiveNetParams = &TestNet3Params
 373  		fork.IsTestnet = true
 374  	}
 375  	if cfg.RegressionTest {
 376  		numNets++
 377  		ActiveNetParams = &RegressionTestParams
 378  		fork.IsTestnet = true
 379  	}
 380  	if cfg.SimNet {
 381  		numNets++
 382  		// Also disable dns seeding on the simulation test network.
 383  		ActiveNetParams = &SimNetParams
 384  		cfg.DisableDNSSeed = true
 385  		fork.IsTestnet = true
 386  	}
 387  	if numNets > 1 {
 388  		str := "%s: The testnet, regtest, segnet, and simnet netparams " +
 389  			"can't be used together -- choose one of the four"
 390  		e := fmt.Errorf(str, funcName)
 391  		fmt.Fprintln(os.Stderr, e)
 392  		fmt.Fprintln(os.Stderr, usageMessage)
 393  		return nil, nil, e
 394  	}
 395  	// Set the mining algorithm correctly, default to sha256d if unrecognised
 396  	switch cfg.Algo {
 397  	case "blake14lr", "cryptonight7v2", "keccak", "lyra2rev2", "scrypt", "skein", "x11", "stribog", "random", "easy":
 398  	default:
 399  		cfg.Algo = fork.SHA256d
 400  	}
 401  	// Set the default policy for relaying non-standard transactions according to the default of the active network. The set configuration value takes precedence over the default value for the selected network.
 402  	relayNonStd := ActiveNetParams.RelayNonStdTxs
 403  	switch {
 404  	case cfg.RelayNonStd && cfg.RejectNonStd:
 405  		str := "%s: rejectnonstd and relaynonstd cannot be used " +
 406  			"together -- choose only one"
 407  		e := fmt.Errorf(str, funcName)
 408  		fmt.Fprintln(os.Stderr, e)
 409  		fmt.Fprintln(os.Stderr, usageMessage)
 410  		return nil, nil, e
 411  	case cfg.RejectNonStd:
 412  		relayNonStd = false
 413  	case cfg.RelayNonStd:
 414  		relayNonStd = true
 415  	}
 416  	cfg.RelayNonStd = relayNonStd
 417  	// Append the network type to the data directory so it is "namespaced" per network.  In addition to the block database, there are other pieces of data that are saved to disk such as address manager state. All data is specific to a network, so namespacing the data directory means each individual piece of serialized data does not have to worry about changing names per network and such.
 418  	cfg.DataDir = CleanAndExpandPath(cfg.DataDir)
 419  	cfg.DataDir = filepath.Join(cfg.DataDir, NetName(ActiveNetParams))
 420  	// Append the network type to the log directory so it is "namespaced" per network in the same fashion as the data directory.
 421  	cfg.LogDir = CleanAndExpandPath(cfg.LogDir)
 422  	cfg.LogDir = filepath.Join(cfg.LogDir, NetName(ActiveNetParams))
 423  	// Initialize log rotation.  After log rotation has been initialized, the logger variables may be used.
 424  	// initLogRotator(filepath.Join(cfg.LogDir, DefaultLogFilename))
 425  	// Validate database type.
 426  	if !ValidDbType(cfg.DbType) {
 427  		str := "%s: The specified database type [%v] is invalid -- supported types %v"
 428  		e := fmt.Errorf(str, funcName, cfg.DbType, KnownDbTypes)
 429  		fmt.Fprintln(os.Stderr, e)
 430  		fmt.Fprintln(os.Stderr, usageMessage)
 431  		return nil, nil, e
 432  	}
 433  	// Validate profile port number
 434  	if cfg.Profile != "" {
 435  		log <- cl.trace{"profiling to", cfg.Profile}
 436  		profilePort, e := strconv.Atoi(cfg.Profile)
 437  		if e != nil  || profilePort < 1024 || profilePort > 65535 {
 438  			str := "%s: The profile port must be between 1024 and 65535"
 439  			e := fmt.Errorf(str, funcName)
 440  			fmt.Fprintln(os.Stderr, e)
 441  			fmt.Fprintln(os.Stderr, usageMessage)
 442  			return nil, nil, e
 443  		}
 444  	}
 445  	// Don't allow ban durations that are too short.
 446  	if cfg.BanDuration < time.Second {
 447  		str := "%s: The banduration opt may not be less than 1s -- parsed [%v]"
 448  		e := fmt.Errorf(str, funcName, cfg.BanDuration)
 449  		fmt.Fprintln(os.Stderr, e)
 450  		fmt.Fprintln(os.Stderr, usageMessage)
 451  		return nil, nil, e
 452  	}
 453  	// Validate any given whitelisted IP addresses and networks.
 454  	if len(StateCfg.ActiveWhitelists) > 0 {
 455  		var ip net.IP
 456  		StateCfg.ActiveWhitelists = make([]*net.IPNet, 0, len(StateCfg.ActiveWhitelists))
 457  		for _, addr := range cfg.Whitelists {
 458  			_, ipnet, e := net.ParseCIDR(addr)
 459  			if e != nil  {
 460  				ip = net.ParseIP(addr)
 461  				if ip == nil {
 462  					str := "%s: The whitelist value of '%s' is invalid"
 463  					e = fmt.Errorf(str, funcName, addr)
 464  					fmt.Fprintln(os.Stderr, e)
 465  					fmt.Fprintln(os.Stderr, usageMessage)
 466  					return nil, nil, e
 467  				}
 468  				var bits int
 469  				if ip.To4() == nil {
 470  					// IPv6
 471  					bits = 128
 472  				} else {
 473  					bits = 32
 474  				}
 475  				ipnet = &net.IPNet{
 476  					IP:   ip,
 477  					Mask: net.CIDRMask(bits, bits),
 478  				}
 479  			}
 480  			StateCfg.ActiveWhitelists = append(StateCfg.ActiveWhitelists, ipnet)
 481  		}
 482  	}
 483  	// --addPeer and --connect do not mix.
 484  	if len(cfg.AddPeers) > 0 && len(cfg.ConnectPeers) > 0 {
 485  		str := "%s: the --addpeer and --connect options can not be " +
 486  			"mixed"
 487  		e := fmt.Errorf(str, funcName)
 488  		fmt.Fprintln(os.Stderr, e)
 489  		fmt.Fprintln(os.Stderr, usageMessage)
 490  		return nil, nil, e
 491  	}
 492  	// --proxy or --connect without --listen disables listening.
 493  	if (cfg.Proxy != "" || len(cfg.ConnectPeers) > 0) &&
 494  		len(cfg.P2PListeners) == 0 {
 495  		cfg.DisableListen = true
 496  	}
 497  	// Connect means no DNS seeding.
 498  	if len(cfg.ConnectPeers) > 0 {
 499  		cfg.DisableDNSSeed = true
 500  	}
 501  	// Add the default listener if none were specified. The default listener is all addresses on the listen port for the network we are to connect to.
 502  	if len(cfg.P2PListeners) == 0 {
 503  		cfg.P2PListeners = []string{
 504  			net.JoinHostPort("", ActiveNetParams.DefaultPort),
 505  		}
 506  	}
 507  	// Chk to make sure limited and admin users don't have the same username
 508  	if cfg.RPCUser == cfg.RPCLimitUser && cfg.RPCUser != "" {
 509  		str := "%s: --rpcuser and --rpclimituser must not specify the " +
 510  			"same username"
 511  		e := fmt.Errorf(str, funcName)
 512  		fmt.Fprintln(os.Stderr, e)
 513  		fmt.Fprintln(os.Stderr, usageMessage)
 514  		return nil, nil, e
 515  	}
 516  	// Chk to make sure limited and admin users don't have the same password
 517  	if cfg.RPCPass == cfg.RPCLimitPass && cfg.RPCPass != "" {
 518  		str := "%s: --rpcpass and --rpclimitpass must not specify the " +
 519  			"same password"
 520  		e := fmt.Errorf(str, funcName)
 521  		fmt.Fprintln(os.Stderr, e)
 522  		fmt.Fprintln(os.Stderr, usageMessage)
 523  		return nil, nil, e
 524  	}
 525  	// The RPC server is disabled if no username or password is provided.
 526  	if (cfg.RPCUser == "" || cfg.RPCPass == "") &&
 527  		(cfg.RPCLimitUser == "" || cfg.RPCLimitPass == "") {
 528  		cfg.DisableRPC = true
 529  	}
 530  	if cfg.DisableRPC {
 531  		log <- cl.Inf("RPC service is disabled")
 532  		// Default RPC to listen on localhost only.
 533  		if !cfg.DisableRPC && len(cfg.RPCListeners) == 0 {
 534  			addrs, e := net.LookupHost("127.0.0.1:11048")
 535  			if e != nil  {
 536  				return nil, nil, e
 537  			}
 538  			cfg.RPCListeners = make([]string, 0, len(addrs))
 539  			for _, addr := range addrs {
 540  				addr = net.JoinHostPort(addr, ActiveNetParams.RPCPort)
 541  				cfg.RPCListeners = append(cfg.RPCListeners, addr)
 542  			}
 543  		}
 544  		if cfg.RPCMaxConcurrentReqs < 0 {
 545  			str := "%s: The rpcmaxwebsocketconcurrentrequests opt may not be less than 0 -- parsed [%d]"
 546  			e := fmt.Errorf(str, funcName, cfg.RPCMaxConcurrentReqs)
 547  			fmt.Fprintln(os.Stderr, e)
 548  			fmt.Fprintln(os.Stderr, usageMessage)
 549  			return nil, nil, e
 550  		}
 551  	}
 552  	// Validate the the minrelaytxfee.
 553  	StateCfg.ActiveMinRelayTxFee, e = util.NewAmount(cfg.MinRelayTxFee)
 554  	if e != nil  {
 555  		str := "%s: invalid minrelaytxfee: %v"
 556  		e := fmt.Errorf(str, funcName, e)
 557  		fmt.Fprintln(os.Stderr, e)
 558  		fmt.Fprintln(os.Stderr, usageMessage)
 559  		return nil, nil, e
 560  	}
 561  	// Limit the max block size to a sane value.
 562  	if cfg.BlockMaxSize < BlockMaxSizeMin || cfg.BlockMaxSize >
 563  		BlockMaxSizeMax {
 564  		str := "%s: The blockmaxsize opt must be in between %d " +
 565  			"and %d -- parsed [%d]"
 566  		e := fmt.Errorf(str, funcName, BlockMaxSizeMin,
 567  			BlockMaxSizeMax, cfg.BlockMaxSize)
 568  		fmt.Fprintln(os.Stderr, e)
 569  		fmt.Fprintln(os.Stderr, usageMessage)
 570  		return nil, nil, e
 571  	}
 572  	// Limit the max block weight to a sane value.
 573  	if cfg.BlockMaxWeight < BlockMaxWeightMin ||
 574  		cfg.BlockMaxWeight > BlockMaxWeightMax {
 575  		str := "%s: The blockmaxweight opt must be in between %d " +
 576  			"and %d -- parsed [%d]"
 577  		e := fmt.Errorf(str, funcName, BlockMaxWeightMin,
 578  			BlockMaxWeightMax, cfg.BlockMaxWeight)
 579  		fmt.Fprintln(os.Stderr, e)
 580  		fmt.Fprintln(os.Stderr, usageMessage)
 581  		return nil, nil, e
 582  	}
 583  	// Limit the max orphan count to a sane vlue.
 584  	if cfg.MaxOrphanTxs < 0 {
 585  		str := "%s: The maxorphantx opt may not be less than 0 " +
 586  			"-- parsed [%d]"
 587  		e := fmt.Errorf(str, funcName, cfg.MaxOrphanTxs)
 588  		fmt.Fprintln(os.Stderr, e)
 589  		fmt.Fprintln(os.Stderr, usageMessage)
 590  		return nil, nil, e
 591  	}
 592  	// Limit the block priority and minimum block txsizes to max block size.
 593  	cfg.BlockPrioritySize = minUint32(cfg.BlockPrioritySize, cfg.BlockMaxSize)
 594  	cfg.BlockMinSize = minUint32(cfg.BlockMinSize, cfg.BlockMaxSize)
 595  	cfg.BlockMinWeight = minUint32(cfg.BlockMinWeight, cfg.BlockMaxWeight)
 596  	switch {
 597  	// If the max block size isn't set, but the max weight is, then we'll set the limit for the max block size to a safe limit so weight takes precedence.
 598  	case cfg.BlockMaxSize == DefaultBlockMaxSize &&
 599  		cfg.BlockMaxWeight != DefaultBlockMaxWeight:
 600  		cfg.BlockMaxSize = blockchain.MaxBlockBaseSize - 1000
 601  	// If the max block weight isn't set, but the block size is, then we'll scale the set weight accordingly based on the max block size value.
 602  	case cfg.BlockMaxSize != DefaultBlockMaxSize &&
 603  		cfg.BlockMaxWeight == DefaultBlockMaxWeight:
 604  		cfg.BlockMaxWeight = cfg.BlockMaxSize * blockchain.WitnessScaleFactor
 605  	}
 606  	// Look for illegal characters in the user agent comments.
 607  	for _, uaComment := range cfg.UserAgentComments {
 608  		if strings.ContainsAny(uaComment, "/:()") {
 609  			e := fmt.Errorf("%s: The following characters must not "+
 610  				"appear in user agent comments: '/', ':', '(', ')'",
 611  				funcName)
 612  			fmt.Fprintln(os.Stderr, e)
 613  			fmt.Fprintln(os.Stderr, usageMessage)
 614  			return nil, nil, e
 615  		}
 616  	}
 617  	// --txindex and --droptxindex do not mix.
 618  	if cfg.TxIndex && cfg.DropTxIndex {
 619  		e := fmt.Errorf("%s: the --txindex and --droptxindex "+
 620  			"options may  not be activated at the same time",
 621  			funcName)
 622  		fmt.Fprintln(os.Stderr, e)
 623  		fmt.Fprintln(os.Stderr, usageMessage)
 624  		return nil, nil, e
 625  	}
 626  	// --addrindex and --dropaddrindex do not mix.
 627  	if cfg.AddrIndex && cfg.DropAddrIndex {
 628  		e := fmt.Errorf("%s: the --addrindex and --dropaddrindex "+
 629  			"options may not be activated at the same time",
 630  			funcName)
 631  		fmt.Fprintln(os.Stderr, e)
 632  		fmt.Fprintln(os.Stderr, usageMessage)
 633  		return nil, nil, e
 634  	}
 635  	// --addrindex and --droptxindex do not mix.
 636  	if cfg.AddrIndex && cfg.DropTxIndex {
 637  		e := fmt.Errorf("%s: the --addrindex and --droptxindex options may not be activated at the same time because the address index relies on the transaction index", funcName)
 638  		fmt.Fprintln(os.Stderr, e)
 639  		fmt.Fprintln(os.Stderr, usageMessage)
 640  		return nil, nil, e
 641  	}
 642  	// Chk mining addresses are valid and saved parsed versions.
 643  	StateCfg.ActiveMiningAddrs = make([]util.Address, 0, len(cfg.MiningAddrs))
 644  	for _, strAddr := range cfg.MiningAddrs {
 645  		addr, e := util.DecodeAddress(strAddr, Activechaincfg.Params)
 646  		if e != nil  {
 647  			str := "%s: mining address '%s' failed to decode: %v"
 648  			e := fmt.Errorf(str, funcName, strAddr, e)
 649  			fmt.Fprintln(os.Stderr, e)
 650  			fmt.Fprintln(os.Stderr, usageMessage)
 651  			return nil, nil, e
 652  		}
 653  		if !addr.IsForNet(Activechaincfg.Params) {
 654  			str := "%s: mining address '%s' is on the wrong network"
 655  			e := fmt.Errorf(str, funcName, strAddr)
 656  			fmt.Fprintln(os.Stderr, e)
 657  			fmt.Fprintln(os.Stderr, usageMessage)
 658  			return nil, nil, e
 659  		}
 660  		StateCfg.ActiveMiningAddrs = append(StateCfg.ActiveMiningAddrs, addr)
 661  	}
 662  	// Ensure there is at least one mining address when the generate flag is set.
 663  	if (cfg.Generate || cfg.MinerListener != "") && len(cfg.MiningAddrs) == 0 {
 664  		str := "%s: the generate flag is set, but there are no mining addresses specified "
 665  		e := fmt.Errorf(str, funcName)
 666  		fmt.Fprintln(os.Stderr, e)
 667  		fmt.Fprintln(os.Stderr, usageMessage)
 668  		return nil, nil, e
 669  	}
 670  	if cfg.MinerPass != "" {
 671  		StateCfg.ActiveMinerKey = fork.Argon2i([]byte(cfg.MinerPass))
 672  	}
 673  	// Add default port to all listener addresses if needed and remove duplicate addresses.
 674  	cfg.P2PListeners = NormalizeAddresses(cfg.P2PListeners,
 675  		ActiveNetParams.DefaultPort)
 676  	// Add default port to all rpc listener addresses if needed and remove duplicate addresses.
 677  	cfg.RPCListeners = NormalizeAddresses(cfg.RPCListeners,
 678  		ActiveNetParams.RPCPort)
 679  	if !cfg.DisableRPC && !cfg.TLS {
 680  		for _, addr := range cfg.RPCListeners {
 681  			if e != nil  {
 682  				str := "%s: RPC listen interface '%s' is invalid: %v"
 683  				e := fmt.Errorf(str, funcName, addr, e)
 684  				fmt.Fprintln(os.Stderr, err)
 685  				fmt.Fprintln(os.Stderr, usageMessage)
 686  				return nil, nil, e
 687  			}
 688  		}
 689  	}
 690  	// Add default port to all added peer addresses if needed and remove duplicate addresses.
 691  	cfg.AddPeers = NormalizeAddresses(cfg.AddPeers,
 692  		ActiveNetParams.DefaultPort)
 693  	cfg.ConnectPeers = NormalizeAddresses(cfg.ConnectPeers,
 694  		ActiveNetParams.DefaultPort)
 695  	// --noonion and --onion do not mix.
 696  	if cfg.NoOnion && cfg.OnionProxy != "" {
 697  		e := fmt.Errorf("%s: the --noonion and --onion options may not be activated at the same time", funcName)
 698  		fmt.Fprintln(os.Stderr, err)
 699  		fmt.Fprintln(os.Stderr, usageMessage)
 700  		return nil, nil, e
 701  	}
 702  	// Chk the checkpoints for syntax errors.
 703  	StateCfg.AddedCheckpoints, e = ParseCheckpoints(cfg.AddCheckpoints)
 704  	if e != nil  {
 705  		str := "%s: DBError parsing checkpoints: %v"
 706  		e := fmt.Errorf(str, funcName, err)
 707  		fmt.Fprintln(os.Stderr, err)
 708  		fmt.Fprintln(os.Stderr, usageMessage)
 709  		return nil, nil, e
 710  	}
 711  	// Tor stream isolation requires either proxy or onion proxy to be set.
 712  	if cfg.TorIsolation && cfg.Proxy == "" && cfg.OnionProxy == "" {
 713  		str := "%s: Tor stream isolation requires either proxy or onionproxy to be set"
 714  		e := fmt.Errorf(str, funcName)
 715  		fmt.Fprintln(os.Stderr, err)
 716  		fmt.Fprintln(os.Stderr, usageMessage)
 717  		return nil, nil, e
 718  	}
 719  	// Setup dial and DNS resolution (lookup) functions depending on the specified options.  The default is to use the standard net.DialTimeout function as well as the system DNS resolver.  When a proxy is specified, the dial function is set to the proxy specific dial function and the lookup is set to use tor (unless --noonion is specified in which case the system DNS resolver is used).
 720  	StateCfg.Dial = net.DialTimeout
 721  	StateCfg.Lookup = net.LookupIP
 722  	if cfg.Proxy != "" {
 723  		_, _, e = net.SplitHostPort(cfg.Proxy)
 724  		if e != nil  {
 725  			str := "%s: Proxy address '%s' is invalid: %v"
 726  			e := fmt.Errorf(str, funcName, cfg.Proxy, err)
 727  			fmt.Fprintln(os.Stderr, err)
 728  			fmt.Fprintln(os.Stderr, usageMessage)
 729  			return nil, nil, e
 730  		}
 731  		// Tor isolation flag means proxy credentials will be overridden unless there is also an onion proxy configured in which case that one will be overridden.
 732  		torIsolation := false
 733  		if cfg.TorIsolation && cfg.OnionProxy == "" &&
 734  			(cfg.ProxyUser != "" || cfg.ProxyPass != "") {
 735  			torIsolation = true
 736  			fmt.Fprintln(os.Stderr, "Tor isolation set -- overriding specified proxy user credentials")
 737  		}
 738  		proxy := &socks.Proxy{
 739  			Addr:         cfg.Proxy,
 740  			Username:     cfg.ProxyUser,
 741  			Password:     cfg.ProxyPass,
 742  			TorIsolation: torIsolation,
 743  		}
 744  		StateCfg.Dial = proxy.DialTimeout
 745  		// Treat the proxy as tor and perform DNS resolution through it unless the --noonion flag is set or there is an onion-specific proxy configured.
 746  		if !cfg.NoOnion && cfg.OnionProxy == "" {
 747  			StateCfg.Lookup = func(host string) ([]net.IP, error) {
 748  				return connmgr.TorLookupIP(host, cfg.Proxy)
 749  			}
 750  		}
 751  	}
 752  	// Setup onion address dial function depending on the specified options. The default is to use the same dial function selected above.  However, when an onion-specific proxy is specified, the onion address dial function is set to use the onion-specific proxy while leaving the normal dial function as selected above.  This allows .onion address traffic to be routed through a different proxy than normal traffic.
 753  	if cfg.OnionProxy != "" {
 754  		_, _, e = net.SplitHostPort(cfg.OnionProxy)
 755  		if e != nil  {
 756  			str := "%s: Onion proxy address '%s' is invalid: %v"
 757  			e := fmt.Errorf(str, funcName, cfg.OnionProxy, err)
 758  			fmt.Fprintln(os.Stderr, err)
 759  			fmt.Fprintln(os.Stderr, usageMessage)
 760  			return nil, nil, e
 761  		}
 762  		// Tor isolation flag means onion proxy credentials will be overridden.
 763  		if cfg.TorIsolation &&
 764  			(cfg.OnionProxyUser != "" || cfg.OnionProxyPass != "") {
 765  			fmt.Fprintln(os.Stderr, "Tor isolation set -- "+
 766  				"overriding specified onionproxy user "+
 767  				"credentials ")
 768  		}
 769  		StateCfg.Oniondial = func(network, addr string, timeout time.Duration) (net.Conn, error) {
 770  			proxy := &socks.Proxy{
 771  				Addr:         cfg.OnionProxy,
 772  				Username:     cfg.OnionProxyUser,
 773  				Password:     cfg.OnionProxyPass,
 774  				TorIsolation: cfg.TorIsolation,
 775  			}
 776  			return proxy.DialTimeout(network, addr, timeout)
 777  		}
 778  		// When configured in bridge mode (both --onion and --proxy are configured), it means that the proxy configured by --proxy is not a tor proxy, so override the DNS resolution to use the onion-specific proxy.
 779  		if cfg.Proxy != "" {
 780  			StateCfg.Lookup = func(host string) ([]net.IP, error) {
 781  				return connmgr.TorLookupIP(host, cfg.OnionProxy)
 782  			}
 783  		}
 784  	} else {
 785  		StateCfg.Oniondial = StateCfg.Dial
 786  	}
 787  	// Specifying --noonion means the onion address dial function results in an error.
 788  	if cfg.NoOnion {
 789  		StateCfg.Oniondial = func(a, b string, t time.Duration) (net.Conn, error) {
 790  			return nil, errors.New("tor has been disabled")
 791  		}
 792  	}
 793  	// wrn about missing config file only after all other configuration is done.  This prevents the warning on help messages and invalid options.  Note this should go directly before the return.
 794  	if configFileError != nil {
 795  		log <- cl.wrn{configFileError}
 796  	}
 797  	return &cfg, remainingArgs, nil
 798  }
 799  // minUint32 is a helper function to return the minimum of two uint32s. This avoids a math import and the need to cast to floats.
 800  func minUint32(	a, b uint32,
 801  	) uint32 {
 802  		if a < b {
 803  			return a
 804  		}
 805  		return b
 806  	}
 807  */
 808