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