diff --git a/btcd.go b/btcd.go index c7f292cbc9..36a764c453 100644 --- a/btcd.go +++ b/btcd.go @@ -17,6 +17,9 @@ import ( "github.com/btcsuite/btcd/blockchain/indexers" "github.com/btcsuite/btcd/database" + "github.com/btcsuite/btcd/internal/config" + "github.com/btcsuite/btcd/internal/log" + "github.com/btcsuite/btcd/internal/params" "github.com/btcsuite/btcd/limits" "github.com/btcsuite/btcd/ossec" ) @@ -29,13 +32,23 @@ const ( ) var ( - cfg *config + cfg *config.Config ) // winServiceMain is only invoked on Windows. It detects when btcd is running // as a service and reacts accordingly. var winServiceMain func() (bool, error) +var ( + btcdLog = log.BtcdLog + srvrLog = log.SrvrLog + rpcsLog = log.RpcsLog + peerLog = log.PeerLog + txmpLog = log.TxmpLog + indxLog = log.IndxLog + amgrLog = log.AmgrLog +) + // btcdMain is the real main function for btcd. It is necessary to work around // the fact that deferred functions do not run when os.Exit() is called. The // optional serverChan parameter is mainly used by the service code to be @@ -44,14 +57,14 @@ var winServiceMain func() (bool, error) func btcdMain(serverChan chan<- *server) error { // Load configuration and parse command line. This function also // initializes logging and configures it accordingly. - tcfg, _, err := loadConfig() + tcfg, _, err := config.LoadConfig(version()) if err != nil { return err } cfg = tcfg defer func() { - if logRotator != nil { - logRotator.Close() + if log.LogRotator != nil { + log.LogRotator.Close() } }() @@ -251,7 +264,7 @@ func btcdMain(serverChan chan<- *server) error { // Create server and start it. server, err := newServer(cfg.Listeners, cfg.AgentBlacklist, - cfg.AgentWhitelist, db, activeNetParams.Params, interrupt) + cfg.AgentWhitelist, db, params.ActiveNetParams.Params, interrupt) if err != nil { // TODO: this logging could do with some beautifying. btcdLog.Errorf("Unable to start server on %v: %v", @@ -376,7 +389,7 @@ func loadBlockDB() (database.DB, error) { removeRegressionDB(dbPath) btcdLog.Infof("Loading block database from '%s'", dbPath) - db, err := database.Open(cfg.DbType, dbPath, activeNetParams.Net) + db, err := database.Open(cfg.DbType, dbPath, params.ActiveNetParams.Net) if err != nil { // Return the error if it's not because the database doesn't // exist. @@ -391,7 +404,7 @@ func loadBlockDB() (database.DB, error) { if err != nil { return nil, err } - db, err = database.Create(cfg.DbType, dbPath, activeNetParams.Net) + db, err = database.Create(cfg.DbType, dbPath, params.ActiveNetParams.Net) if err != nil { return nil, err } @@ -456,3 +469,13 @@ func main() { os.Exit(1) } } + +// fileExists reports whether the named file or directory exists. +func fileExists(name string) bool { + if _, err := os.Stat(name); err != nil { + if os.IsNotExist(err) { + return false + } + } + return true +} diff --git a/btcdctrl/btcdctrl.go b/btcdctrl/btcdctrl.go new file mode 100644 index 0000000000..fde3abe849 --- /dev/null +++ b/btcdctrl/btcdctrl.go @@ -0,0 +1,381 @@ +package btcdctrl + +import ( + "bufio" + "errors" + "fmt" + "io" + "os" + "os/exec" + "reflect" + "strconv" + "strings" + "time" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/internal/config" + "github.com/btcsuite/btcd/rpcclient" +) + +type Config = config.Config + +func NewDefaultConfig() *Config { + cfg := config.NewDefaultConfig() + + // Remove the configuration file, as everything is supplied in flags. + cfg.ConfigFile = "" + + return &cfg +} + +// Create a new random address. +func newRandAddress(chain *chaincfg.Params) (btcutil.Address, error) { + // Generate a new private key. + prv, err := btcec.NewPrivateKey() + if err != nil { + return nil, err + } + + // Derive a public key, then serialize it. + pk := prv.PubKey().SerializeUncompressed() + + // Create a new pay-to-pubkey address. + return btcutil.NewAddressPubKey(pk, chain) +} + +func NewTestConfig(tmp string) (*Config, error) { + cfg := NewDefaultConfig() + + // Set the network to simnet. + cfg.SimNet = true + + // Enable generating blocks. + cfg.Generate = true + + // Create a new random address. + addr, err := newRandAddress(&chaincfg.SimNetParams) + if err != nil { + return nil, err + } + + // Use the random address as the mining address, required for generate. + cfg.MiningAddrs = []btcutil.Address{addr} + + // Set the default credentials to user:pass. + cfg.RPCUser = "user" + cfg.RPCPass = "pass" + + // Change the root directory to the temporary directory. + cfg.ChangeRoot(tmp) + + // Listen on 127.0.0.1 on an OS assigned port. + cfg.RPCListeners = []string{"127.0.0.1:0"} + cfg.Listeners = []string{"127.0.0.1:0"} + + return cfg, nil +} + +type ControllerConfig struct { + Stderr io.Writer + Stdout io.Writer + + Path string + + *Config +} + +type Controller struct { + *rpcclient.Client + + cmd *exec.Cmd + + rpc string + p2p string + + cfg *ControllerConfig +} + +// gracefully shutdown btcd instance using SIGINT and wait for it to exit. +func (c *Controller) Stop() error { + // Signal SIGINT, for graceful shutdown. + err := c.cmd.Process.Signal(os.Interrupt) + if err != nil { + return err + } + + // Wait for the program to exit. + for { + exit, err := c.cmd.Process.Wait() + if err != nil { + break + } + + // Check if the program exited. + if exit.Exited() { + break + } + } + + return nil +} + +func (c *Controller) RPCAddress() string { + return c.rpc +} + +func (c *Controller) P2PAddress() string { + return c.p2p +} + +func (c *Controller) RPCConnConfig() (*rpcclient.ConnConfig, error) { + cert, err := os.ReadFile(c.cfg.Config.RPCCert) + if err != nil { + return nil, err + } + + return &rpcclient.ConnConfig{ + Host: c.rpc, + + User: c.cfg.RPCUser, + Pass: c.cfg.RPCPass, + + Certificates: cert, + + HTTPPostMode: true, + }, nil +} + +// Start btcd and wait for the RPC to be ready. +func (c *Controller) Start() error { + var args []string + + // First, we convert the `Config` type into flags. + + // struct value. + sv := reflect.ValueOf(*c.cfg.Config) + + // Iterate over visible fields. + for i, ft := range reflect.VisibleFields(sv.Type()) { + // Skip unexported fields, unused by the flag parser. + if !ft.IsExported() { + continue + } + + // Check for a long tag, we'll use this over the short tag to ease debugging. + name := ft.Tag.Get("long") + + // Skip any fields without a tag, likely unused by the flag parser. + if name == "" { + continue + } + + // Get the field value. + fv := sv.Field(i) + + var val string + + // Encode the field value to a string. + switch iface := fv.Interface(); field := iface.(type) { + case time.Duration: + // Encode the duration into milliseconds. + val = fmt.Sprintf("%dms", field.Milliseconds()) + + case string: + // Skip empty fields, indicating they're unused. + if field == "" { + continue + } + + // Quote the string to avoid command injection. + val = strconv.Quote(field) + + case []string: + // Skip empty slices, indicates unused. + if len(field) == 0 { + continue + } + + // Handle listeners differently, each of them need their own flag. + if name == "listen" || name == "rpclisten" { + for _, f := range field { + args = append(args, fmt.Sprintf("--%s", name), strconv.Quote(f)) + } + + continue + } + + // Quote the string to avoid command injection. + val = strconv.Quote(strings.Join(field, ",")) + + case bool: + // Lack of the flag means false, so skip. + if !field { + continue + } + + // Encode all numbers via `fmt`, handles edge cases for us. + case float64: + val = fmt.Sprintf("%f", fv.Float()) + + case uint, uint16, uint32, uint64: + val = fmt.Sprintf("%d", fv.Uint()) + + case int, int16, int32, int64, btcutil.Amount: + val = fmt.Sprintf("%d", fv.Int()) + + // Technically a valid value for slices, should be skipped. + case nil: + continue + + default: + return errors.New("unknown type") + } + + // Append the flag name. + args = append(args, fmt.Sprintf("--%s", name)) + + // Append the flag value if found (skipped on bools). + if val != "" { + args = append(args, val) + } + } + + // Handle fields that depend on custom encoding/decoding. + + // Encode checkpoints. + for _, chk := range c.cfg.Config.AddCheckpoints { + args = append(args, "--addcheckpoint", fmt.Sprintf("%d:%s", chk.Height, chk.Hash)) + } + + // Encode mining addresses. + for _, addr := range c.cfg.Config.MiningAddrs { + args = append(args, "--miningaddr", addr.EncodeAddress()) + } + + // Encode whitelists. + for _, addr := range c.cfg.Config.Whitelists { + args = append(args, "--whitelist", addr.String()) + } + + name := "btcd" + if c.cfg.Path != "" { + name = c.cfg.Path + } + + // Create the command. + c.cmd = exec.Command(name, args...) + + // Create a pipe of stdout. + pr, pw, err := os.Pipe() + if err != nil { + return err + } + + // Match the output configuration. + c.cmd.Stderr = c.cfg.Stderr + c.cmd.Stdout = pw + + // Execute the command. + err = c.cmd.Start() + if err != nil { + return err + } + + var r io.Reader = pr + + // Pipe the early output to stdout if configured. + if c.cfg.Stdout != nil { + r = io.TeeReader(pr, c.cfg.Stdout) + } + + // Scan the stdout line by line. + scan := bufio.NewScanner(r) + + rpc := c.cfg.DisableRPC + p2p := false + + // Scan each line until both RPC (if enabled) and P2P addresses are found. + for !rpc || !p2p { + line := scan.Text() + + _, addr, ok := strings.Cut(line, "RPC server listening on ") + if ok { + c.rpc = addr + rpc = true + } + + _, addr, ok = strings.Cut(line, "Server listening on ") + if !ok { + c.p2p = addr + p2p = true + } + + // Ensure we've not found the RPC and P2P addresses, so we can continue scanning. + if (!rpc || !p2p) && !scan.Scan() { + break + } + } + + // Return early if RPC is disabled. + if !rpc { + return nil + } + + // Discard as a fallback. + stdout := io.Discard + + // Use the configured stdout by default. + if c.cfg.Stdout != nil { + stdout = c.cfg.Stdout + } + + // The pipe needs to continuously be read, otherwise `btcd` will hang. + go io.Copy(stdout, pr) + + deadline := time.Now().Add(30 * time.Second) + + // Try to connect via RPC for 30 seconds. + for deadline.After(time.Now()) { + var cfg *rpcclient.ConnConfig + // Create the RPC config. + cfg, err = c.RPCConnConfig() + if err != nil { + continue + } + + // Create the RPC client. + c.Client, err = rpcclient.New(cfg, nil) + if err != nil { + continue + } + + // Ping the RPC client. + err = c.Client.Ping() + if err != nil { + continue + } + + err = nil + break + } + + // Check if the connection loop exited with an error. + if err != nil { + return errors.Join(errors.New("timeout"), err) + } + + // Check if the client was created. + if c.Client == nil { + return errors.New("timeout") + } + + return nil +} + +func New(cfg *ControllerConfig) *Controller { + return &Controller{ + cfg: cfg, + } +} diff --git a/btcdctrl/btcdctrl_test.go b/btcdctrl/btcdctrl_test.go new file mode 100644 index 0000000000..b1431c2132 --- /dev/null +++ b/btcdctrl/btcdctrl_test.go @@ -0,0 +1,37 @@ +package btcdctrl + +import ( + "os" + "testing" +) + +func TestFail(t *testing.T) { + for i := 0; i < 100; i++ { + cfg, err := NewTestConfig(t.TempDir()) + if err != nil { + t.Fatal(err) + } + + cfg.DebugLevel = "trace" + + // Create a new controller. + c := New(&ControllerConfig{ + Stderr: os.Stderr, + Stdout: os.Stdout, + + Config: cfg, + }) + + // Start btcd. + err = c.Start() + if err != nil { + t.Fatal(err) + } + + // Stop btcd. + err = c.Stop() + if err != nil { + t.Fatal(err) + } + } +} diff --git a/btcdctrl/example_test.go b/btcdctrl/example_test.go new file mode 100644 index 0000000000..cbc21291c7 --- /dev/null +++ b/btcdctrl/example_test.go @@ -0,0 +1,57 @@ +package btcdctrl_test + +import ( + "fmt" + "os" + + "github.com/btcsuite/btcd/btcdctrl" +) + +func ExampleController() { + // Create a temporary directory for the wallet data. + tmp, err := os.MkdirTemp("", "") + if err != nil { + panic(err) + } + + // Create a new test-oriented configration. + cfg, err := btcdctrl.NewTestConfig(tmp) + if err != nil { + panic(err) + } + + // Create a new controller. + c := btcdctrl.New(&btcdctrl.ControllerConfig{ + Config: cfg, + }) + + // Start btcd. + err = c.Start() + if err != nil { + panic(err) + } + + // Stop btcd on exit. + defer c.Stop() + + // Enable generation. + err = c.SetGenerate(true, 0) + if err != nil { + panic(err) + } + + // Generate 100 blocks. + _, err = c.Generate(100) + if err != nil { + panic(err) + } + + // Query info. + info, err := c.GetInfo() + if err != nil { + panic(err) + } + + fmt.Println(info.Blocks) + // Output: 100 +} diff --git a/config.go b/internal/config/config.go similarity index 83% rename from config.go rename to internal/config/config.go index 9bbce7f69a..a3e1ad5d7e 100644 --- a/config.go +++ b/internal/config/config.go @@ -2,7 +2,7 @@ // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package main +package config import ( "bufio" @@ -28,6 +28,8 @@ import ( "github.com/btcsuite/btcd/connmgr" "github.com/btcsuite/btcd/database" _ "github.com/btcsuite/btcd/database/ffldb" + "github.com/btcsuite/btcd/internal/log" + "github.com/btcsuite/btcd/internal/params" "github.com/btcsuite/btcd/mempool" "github.com/btcsuite/btcd/peer" "github.com/btcsuite/btcd/wire" @@ -36,48 +38,48 @@ import ( ) const ( - defaultConfigFilename = "btcd.conf" - defaultDataDirname = "data" - defaultLogLevel = "info" - defaultLogDirname = "logs" - defaultLogFilename = "btcd.log" - defaultMaxPeers = 125 - defaultBanDuration = time.Hour * 24 - defaultBanThreshold = 100 - defaultConnectTimeout = time.Second * 30 - defaultMaxRPCClients = 10 - defaultMaxRPCWebsockets = 25 - defaultMaxRPCConcurrentReqs = 20 - defaultDbType = "ffldb" - defaultFreeTxRelayLimit = 15.0 - defaultTrickleInterval = peer.DefaultTrickleInterval - defaultBlockMinSize = 0 - defaultBlockMaxSize = 750000 - defaultBlockMinWeight = 0 - defaultBlockMaxWeight = 3000000 - blockMaxSizeMin = 1000 - blockMaxSizeMax = blockchain.MaxBlockBaseSize - 1000 - blockMaxWeightMin = 4000 - blockMaxWeightMax = blockchain.MaxBlockWeight - 4000 - defaultGenerate = false - defaultMaxOrphanTransactions = 100 - defaultMaxOrphanTxSize = 100000 - defaultSigCacheMaxSize = 100000 - defaultUtxoCacheMaxSizeMiB = 250 - sampleConfigFilename = "sample-btcd.conf" - defaultTxIndex = false - defaultAddrIndex = false - pruneMinSize = 1536 + DefaultConfigFilename = "btcd.conf" + DefaultDataDirname = "data" + DefaultLogLevel = "info" + DefaultLogDirname = "logs" + DefaultLogFilename = "btcd.log" + DefaultMaxPeers = 125 + DefaultBanDuration = time.Hour * 24 + DefaultBanThreshold = 100 + DefaultConnectTimeout = time.Second * 30 + DefaultMaxRPCClients = 10 + DefaultMaxRPCWebsockets = 25 + DefaultMaxRPCConcurrentReqs = 20 + DefaultDbType = "ffldb" + DefaultFreeTxRelayLimit = 15.0 + DefaultTrickleInterval = peer.DefaultTrickleInterval + DefaultBlockMinSize = 0 + DefaultBlockMaxSize = 750000 + DefaultBlockMinWeight = 0 + DefaultBlockMaxWeight = 3000000 + BlockMaxSizeMin = 1000 + BlockMaxSizeMax = blockchain.MaxBlockBaseSize - 1000 + BlockMaxWeightMin = 4000 + BlockMaxWeightMax = blockchain.MaxBlockWeight - 4000 + DefaultGenerate = false + DefaultMaxOrphanTransactions = 100 + DefaultMaxOrphanTxSize = 100000 + DefaultSigCacheMaxSize = 100000 + DefaultUtxoCacheMaxSizeMiB = 250 + SampleConfigFilename = "../../sample-btcd.conf" + DefaultTxIndex = false + DefaultAddrIndex = false + PruneMinSize = 1536 ) var ( - defaultHomeDir = btcutil.AppDataDir("btcd", false) - defaultConfigFile = filepath.Join(defaultHomeDir, defaultConfigFilename) - defaultDataDir = filepath.Join(defaultHomeDir, defaultDataDirname) - knownDbTypes = database.SupportedDrivers() - defaultRPCKeyFile = filepath.Join(defaultHomeDir, "rpc.key") - defaultRPCCertFile = filepath.Join(defaultHomeDir, "rpc.cert") - defaultLogDir = filepath.Join(defaultHomeDir, defaultLogDirname) + DefaultHomeDir = btcutil.AppDataDir("btcd", false) + DefaultConfigFile = filepath.Join(DefaultHomeDir, DefaultConfigFilename) + DefaultDataDir = filepath.Join(DefaultHomeDir, DefaultDataDirname) + KnownDbTypes = database.SupportedDrivers() + DefaultRPCKeyFile = filepath.Join(DefaultHomeDir, "rpc.key") + DefaultRPCCertFile = filepath.Join(DefaultHomeDir, "rpc.cert") + DefaultLogDir = filepath.Join(DefaultHomeDir, DefaultLogDirname) ) // runServiceCommand is only set to a real function on Windows. It is used @@ -93,11 +95,7 @@ func minUint32(a, b uint32) uint32 { return b } -// config defines the configuration options for btcd. -// -// See loadConfig for details on the configuration load process. -type config struct { - AddCheckpoints []string `long:"addcheckpoint" description:"Add a custom checkpoint. Format: ':'"` +type Config struct { AddPeers []string `short:"a" long:"addpeer" description:"Add a peer to connect with at startup"` AddrIndex bool `long:"addrindex" description:"Maintain a full address-based transaction index which makes the searchrawtransactions RPC available"` AgentBlacklist []string `long:"agentblacklist" description:"A comma separated list of user-agent substrings which will cause btcd to reject any peers whose user-agent contains any of the blacklisted substrings."` @@ -127,8 +125,6 @@ type config struct { LogDir string `long:"logdir" description:"Directory to log output."` MaxOrphanTxs int `long:"maxorphantx" description:"Max number of orphan transactions to keep in memory"` MaxPeers int `long:"maxpeers" description:"Max number of inbound and outbound peers"` - MiningAddrs []string `long:"miningaddr" description:"Add the specified payment address to the list of addresses to use for generated blocks -- At least one address is required if the generate option is set"` - MinRelayTxFee float64 `long:"minrelaytxfee" description:"The minimum transaction fee in BTC/kB to be considered a non-zero fee."` DisableBanning bool `long:"nobanning" description:"Disable banning of misbehaving peers"` NoCFilters bool `long:"nocfilters" description:"Disable committed filtering (CF) support"` DisableCheckpoints bool `long:"nocheckpoints" description:"Disable built-in checkpoints. Don't do this unless you know what you're doing."` @@ -177,14 +173,64 @@ type config struct { UserAgentComments []string `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."` Upnp bool `long:"upnp" description:"Use UPnP to map our listening port outside of NAT"` ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"` - Whitelists []string `long:"whitelist" description:"Add an IP network or IP that will not be banned. (eg. 192.168.1.0/24 or ::1)"` - lookup func(string) ([]net.IP, error) - oniondial func(string, string, time.Duration) (net.Conn, error) - dial func(string, string, time.Duration) (net.Conn, error) - addCheckpoints []chaincfg.Checkpoint - miningAddrs []btcutil.Address - minRelayTxFee btcutil.Amount - whitelists []*net.IPNet + + AddCheckpoints []chaincfg.Checkpoint + MiningAddrs []btcutil.Address + MinRelayTxFee btcutil.Amount + Whitelists []*net.IPNet + + lookup func(string) ([]net.IP, error) + oniondial func(string, string, time.Duration) (net.Conn, error) + dial func(string, string, time.Duration) (net.Conn, error) +} + +func (cfg *Config) ChangeRoot(root string) { + cfg.LogDir = filepath.Join(root, "data") + cfg.RPCKey = filepath.Join(root, "rpc.key") + cfg.DataDir = filepath.Join(root, "data") + cfg.RPCCert = filepath.Join(root, "rpc.cert") + + // Only change the configuration file if supplied with one. + if cfg.ConfigFile != "" { + cfg.ConfigFile = filepath.Join(root, "btcd.conf") + } +} + +// Dial connects to the address on the named network using the appropriate +// dial function depending on the address and configuration options. For +// example, .onion addresses will be dialed using the onion specific proxy if +// one was specified, but will otherwise use the normal dial function (which +// could itself use a proxy or not). +func (cfg *Config) Dial(addr net.Addr) (net.Conn, error) { + if strings.Contains(addr.String(), ".onion:") { + return cfg.oniondial(addr.Network(), addr.String(), + DefaultConnectTimeout) + } + return cfg.dial(addr.Network(), addr.String(), DefaultConnectTimeout) +} + +// Lookup resolves the IP of the given host using the correct DNS lookup +// function depending on the configuration options. For example, addresses will +// be resolved using tor when the --proxy flag was specified unless --noonion +// was also specified in which case the normal system DNS resolver will be used. +// +// Any attempt to resolve a tor address (.onion) will return an error since they +// are not intended to be resolved outside of the tor proxy. +func (cfg *Config) Lookup(host string) ([]net.IP, error) { + if strings.HasSuffix(host, ".onion") { + return nil, fmt.Errorf("attempt to resolve tor address %s", host) + } + + return cfg.lookup(host) +} + +type config struct { + Config + + AddCheckpoints []string `long:"addcheckpoint" description:"Add a custom checkpoint. Format: ':'"` + MiningAddrs []string `long:"miningaddr" description:"Add the specified payment address to the list of addresses to use for generated blocks -- At least one address is required if the generate option is set"` + MinRelayTxFee float64 `long:"minrelaytxfee" description:"The minimum transaction fee in BTC/kB to be considered a non-zero fee."` + Whitelists []string `long:"whitelist" description:"Add an IP network or IP that will not be banned. (eg. 192.168.1.0/24 or ::1)"` } // serviceOptions defines the configuration options for the daemon as a service on @@ -198,7 +244,7 @@ type serviceOptions struct { func cleanAndExpandPath(path string) string { // Expand initial ~ to OS specific home directory. if strings.HasPrefix(path, "~") { - homeDir := filepath.Dir(defaultHomeDir) + homeDir := filepath.Dir(DefaultHomeDir) path = strings.Replace(path, "~", homeDir, 1) } @@ -226,12 +272,12 @@ func validLogLevel(logLevel string) bool { return false } -// supportedSubsystems returns a sorted slice of the supported subsystems for +// SupportedSubsystems returns a sorted slice of the supported subsystems for // logging purposes. -func supportedSubsystems() []string { +func SupportedSubsystems() []string { // Convert the subsystemLoggers map keys to a slice. - subsystems := make([]string, 0, len(subsystemLoggers)) - for subsysID := range subsystemLoggers { + subsystems := make([]string, 0, len(log.SubsystemLoggers)) + for subsysID := range log.SubsystemLoggers { subsystems = append(subsystems, subsysID) } @@ -240,10 +286,10 @@ func supportedSubsystems() []string { return subsystems } -// parseAndSetDebugLevels attempts to parse the specified debug level and set +// ParseAndSetDebugLevels attempts to parse the specified debug level and set // the levels accordingly. An appropriate error is returned if anything is // invalid. -func parseAndSetDebugLevels(debugLevel string) error { +func ParseAndSetDebugLevels(debugLevel string) error { // When the specified string doesn't have any delimiters, treat it as // the log level for all subsystems. if !strings.Contains(debugLevel, ",") && !strings.Contains(debugLevel, "=") { @@ -254,7 +300,7 @@ func parseAndSetDebugLevels(debugLevel string) error { } // Change the logging level for all subsystems. - setLogLevels(debugLevel) + log.SetLogLevels(debugLevel) return nil } @@ -273,10 +319,10 @@ func parseAndSetDebugLevels(debugLevel string) error { subsysID, logLevel := fields[0], fields[1] // Validate subsystem. - if _, exists := subsystemLoggers[subsysID]; !exists { + if _, exists := log.SubsystemLoggers[subsysID]; !exists { str := "The specified subsystem [%v] is invalid -- " + "supported subsystems %v" - return fmt.Errorf(str, subsysID, supportedSubsystems()) + return fmt.Errorf(str, subsysID, SupportedSubsystems()) } // Validate log level. @@ -285,7 +331,7 @@ func parseAndSetDebugLevels(debugLevel string) error { return fmt.Errorf(str, logLevel) } - setLogLevel(subsysID, logLevel) + log.SetLogLevel(subsysID, logLevel) } return nil @@ -293,7 +339,7 @@ func parseAndSetDebugLevels(debugLevel string) error { // validDbType returns whether or not dbType is a supported database type. func validDbType(dbType string) bool { - for _, knownType := range knownDbTypes { + for _, knownType := range KnownDbTypes { if dbType == knownType { return true } @@ -316,9 +362,9 @@ func removeDuplicateAddresses(addrs []string) []string { return result } -// normalizeAddress returns addr with the passed default port appended if +// NormalizeAddress returns addr with the passed default port appended if // there is not already a port specified. -func normalizeAddress(addr, defaultPort string) string { +func NormalizeAddress(addr, defaultPort string) string { _, _, err := net.SplitHostPort(addr) if err != nil { return net.JoinHostPort(addr, defaultPort) @@ -330,7 +376,7 @@ func normalizeAddress(addr, defaultPort string) string { // normalized with the given default port, and all duplicates removed. func normalizeAddresses(addrs []string, defaultPort string) []string { for i, addr := range addrs { - addrs[i] = normalizeAddress(addr, defaultPort) + addrs[i] = NormalizeAddress(addr, defaultPort) } return removeDuplicateAddresses(addrs) @@ -403,7 +449,39 @@ func newConfigParser(cfg *config, so *serviceOptions, options flags.Options) *fl return parser } -// loadConfig initializes and parses the config using a config file and command +func NewDefaultConfig() Config { + return Config{ + ConfigFile: DefaultConfigFile, + DebugLevel: DefaultLogLevel, + MaxPeers: DefaultMaxPeers, + BanDuration: DefaultBanDuration, + BanThreshold: DefaultBanThreshold, + RPCMaxClients: DefaultMaxRPCClients, + RPCMaxWebsockets: DefaultMaxRPCWebsockets, + RPCMaxConcurrentReqs: DefaultMaxRPCConcurrentReqs, + DataDir: DefaultDataDir, + LogDir: DefaultLogDir, + DbType: DefaultDbType, + RPCKey: DefaultRPCKeyFile, + RPCCert: DefaultRPCCertFile, + FreeTxRelayLimit: DefaultFreeTxRelayLimit, + TrickleInterval: DefaultTrickleInterval, + BlockMinSize: DefaultBlockMinSize, + BlockMaxSize: DefaultBlockMaxSize, + BlockMinWeight: DefaultBlockMinWeight, + BlockMaxWeight: DefaultBlockMaxWeight, + BlockPrioritySize: mempool.DefaultBlockPrioritySize, + MaxOrphanTxs: DefaultMaxOrphanTransactions, + SigCacheMaxSize: DefaultSigCacheMaxSize, + UtxoCacheMaxSizeMiB: DefaultUtxoCacheMaxSizeMiB, + Generate: DefaultGenerate, + TxIndex: DefaultTxIndex, + AddrIndex: DefaultAddrIndex, + MinRelayTxFee: mempool.DefaultMinRelayTxFee, + } +} + +// LoadConfig initializes and parses the config using a config file and command // line options. // // The configuration proceeds as follows: @@ -415,36 +493,11 @@ func newConfigParser(cfg *config, so *serviceOptions, options flags.Options) *fl // The above results in btcd 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. -func loadConfig() (*config, []string, error) { +func LoadConfig(version string) (*Config, []string, error) { // Default config. cfg := config{ - ConfigFile: defaultConfigFile, - DebugLevel: defaultLogLevel, - MaxPeers: defaultMaxPeers, - BanDuration: defaultBanDuration, - BanThreshold: defaultBanThreshold, - RPCMaxClients: defaultMaxRPCClients, - RPCMaxWebsockets: defaultMaxRPCWebsockets, - RPCMaxConcurrentReqs: defaultMaxRPCConcurrentReqs, - DataDir: defaultDataDir, - LogDir: defaultLogDir, - DbType: defaultDbType, - RPCKey: defaultRPCKeyFile, - RPCCert: defaultRPCCertFile, - MinRelayTxFee: mempool.DefaultMinRelayTxFee.ToBTC(), - FreeTxRelayLimit: defaultFreeTxRelayLimit, - TrickleInterval: defaultTrickleInterval, - BlockMinSize: defaultBlockMinSize, - BlockMaxSize: defaultBlockMaxSize, - BlockMinWeight: defaultBlockMinWeight, - BlockMaxWeight: defaultBlockMaxWeight, - BlockPrioritySize: mempool.DefaultBlockPrioritySize, - MaxOrphanTxs: defaultMaxOrphanTransactions, - SigCacheMaxSize: defaultSigCacheMaxSize, - UtxoCacheMaxSizeMiB: defaultUtxoCacheMaxSizeMiB, - Generate: defaultGenerate, - TxIndex: defaultTxIndex, - AddrIndex: defaultAddrIndex, + Config: NewDefaultConfig(), + MinRelayTxFee: mempool.DefaultMinRelayTxFee.ToBTC(), } // Service options which are only added on Windows. @@ -469,7 +522,7 @@ func loadConfig() (*config, []string, error) { appName = strings.TrimSuffix(appName, filepath.Ext(appName)) usageMessage := fmt.Sprintf("Use %s -h to show usage", appName) if preCfg.ShowVersion { - fmt.Println(appName, "version", version()) + fmt.Println(appName, "version", version) os.Exit(0) } @@ -488,7 +541,7 @@ func loadConfig() (*config, []string, error) { var configFileError error parser := newConfigParser(&cfg, &serviceOpts, flags.Default) if !(preCfg.RegressionTest || preCfg.SimNet || preCfg.SigNet) || - preCfg.ConfigFile != defaultConfigFile { + preCfg.ConfigFile != DefaultConfigFile { if _, err := os.Stat(preCfg.ConfigFile); os.IsNotExist(err) { err := createDefaultConfigFile(preCfg.ConfigFile) @@ -526,7 +579,7 @@ func loadConfig() (*config, []string, error) { // Create the home directory if it doesn't already exist. funcName := "loadConfig" - err = os.MkdirAll(defaultHomeDir, 0700) + err = os.MkdirAll(DefaultHomeDir, 0700) if err != nil { // Show a nicer error message if it's because a symlink is // linked to a directory that does not exist (probably because @@ -550,21 +603,21 @@ func loadConfig() (*config, []string, error) { // while we're at it if cfg.TestNet3 { numNets++ - activeNetParams = &testNet3Params + params.ActiveNetParams = ¶ms.TestNet3Params } if cfg.RegressionTest { numNets++ - activeNetParams = ®ressionNetParams + params.ActiveNetParams = ¶ms.RegressionNetParams } if cfg.SimNet { numNets++ // Also disable dns seeding on the simulation test network. - activeNetParams = &simNetParams + params.ActiveNetParams = ¶ms.SimNetParams cfg.DisableDNSSeed = true } if cfg.SigNet { numNets++ - activeNetParams = &sigNetParams + params.ActiveNetParams = ¶ms.SigNetParams // Let the user overwrite the default signet parameters. The // challenge defines the actual signet network to join and the @@ -599,7 +652,7 @@ func loadConfig() (*config, []string, error) { chainParams := chaincfg.CustomSignetParams( sigNetChallenge, sigNetSeeds, ) - activeNetParams.Params = &chainParams + params.ActiveNetParams.Params = &chainParams } if numNets > 1 { str := "%s: The testnet, regtest, segnet, signet and simnet " + @@ -613,7 +666,7 @@ func loadConfig() (*config, []string, error) { // If mainnet is active, then we won't allow the stall handler to be // disabled. - if activeNetParams.Params.Net == wire.MainNet && cfg.DisableStallHandler { + if params.ActiveNetParams.Params.Net == wire.MainNet && cfg.DisableStallHandler { str := "%s: stall handler cannot be disabled on mainnet" err := fmt.Errorf(str, funcName) fmt.Fprintln(os.Stderr, err) @@ -625,7 +678,7 @@ func loadConfig() (*config, []string, error) { // according to the default of the active network. The set // configuration value takes precedence over the default value for the // selected network. - relayNonStd := activeNetParams.RelayNonStdTxs + relayNonStd := params.ActiveNetParams.RelayNonStdTxs switch { case cfg.RelayNonStd && cfg.RejectNonStd: str := "%s: rejectnonstd and relaynonstd cannot be used " + @@ -648,25 +701,25 @@ func loadConfig() (*config, []string, error) { // means each individual piece of serialized data does not have to // worry about changing names per network and such. cfg.DataDir = cleanAndExpandPath(cfg.DataDir) - cfg.DataDir = filepath.Join(cfg.DataDir, netName(activeNetParams)) + cfg.DataDir = filepath.Join(cfg.DataDir, params.NetName(params.ActiveNetParams)) // Append the network type to the log directory so it is "namespaced" // per network in the same fashion as the data directory. cfg.LogDir = cleanAndExpandPath(cfg.LogDir) - cfg.LogDir = filepath.Join(cfg.LogDir, netName(activeNetParams)) + cfg.LogDir = filepath.Join(cfg.LogDir, params.NetName(params.ActiveNetParams)) // Special show command to list supported subsystems and exit. if cfg.DebugLevel == "show" { - fmt.Println("Supported subsystems", supportedSubsystems()) + fmt.Println("Supported subsystems", SupportedSubsystems()) os.Exit(0) } // Initialize log rotation. After log rotation has been initialized, the // logger variables may be used. - initLogRotator(filepath.Join(cfg.LogDir, defaultLogFilename)) + log.InitLogRotator(filepath.Join(cfg.LogDir, DefaultLogFilename)) // Parse, validate, and set debug log level(s). - if err := parseAndSetDebugLevels(cfg.DebugLevel); err != nil { + if err := ParseAndSetDebugLevels(cfg.DebugLevel); err != nil { err := fmt.Errorf("%s: %v", funcName, err.Error()) fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, usageMessage) @@ -677,7 +730,7 @@ func loadConfig() (*config, []string, error) { if !validDbType(cfg.DbType) { str := "%s: The specified database type [%v] is invalid -- " + "supported types %v" - err := fmt.Errorf(str, funcName, cfg.DbType, knownDbTypes) + err := fmt.Errorf(str, funcName, cfg.DbType, KnownDbTypes) fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, usageMessage) return nil, nil, err @@ -707,7 +760,7 @@ func loadConfig() (*config, []string, error) { // Validate any given whitelisted IP addresses and networks. if len(cfg.Whitelists) > 0 { var ip net.IP - cfg.whitelists = make([]*net.IPNet, 0, len(cfg.Whitelists)) + cfg.Config.Whitelists = make([]*net.IPNet, 0, len(cfg.Whitelists)) for _, addr := range cfg.Whitelists { _, ipnet, err := net.ParseCIDR(addr) @@ -732,7 +785,7 @@ func loadConfig() (*config, []string, error) { Mask: net.CIDRMask(bits, bits), } } - cfg.whitelists = append(cfg.whitelists, ipnet) + cfg.Config.Whitelists = append(cfg.Config.Whitelists, ipnet) } } @@ -762,7 +815,7 @@ func loadConfig() (*config, []string, error) { // we are to connect to. if len(cfg.Listeners) == 0 { cfg.Listeners = []string{ - net.JoinHostPort("", activeNetParams.DefaultPort), + net.JoinHostPort("", params.ActiveNetParams.DefaultPort), } } @@ -793,7 +846,7 @@ func loadConfig() (*config, []string, error) { } if cfg.DisableRPC { - btcdLog.Infof("RPC service is disabled") + log.BtcdLog.Infof("RPC service is disabled") } // Default RPC to listen on localhost only. @@ -804,7 +857,7 @@ func loadConfig() (*config, []string, error) { } cfg.RPCListeners = make([]string, 0, len(addrs)) for _, addr := range addrs { - addr = net.JoinHostPort(addr, activeNetParams.rpcPort) + addr = net.JoinHostPort(addr, params.ActiveNetParams.RPCPort) cfg.RPCListeners = append(cfg.RPCListeners, addr) } } @@ -819,7 +872,7 @@ func loadConfig() (*config, []string, error) { } // Validate the minrelaytxfee. - cfg.minRelayTxFee, err = btcutil.NewAmount(cfg.MinRelayTxFee) + cfg.Config.MinRelayTxFee, err = btcutil.NewAmount(cfg.MinRelayTxFee) if err != nil { str := "%s: invalid minrelaytxfee: %v" err := fmt.Errorf(str, funcName, err) @@ -829,26 +882,26 @@ func loadConfig() (*config, []string, error) { } // Limit the max block size to a sane value. - if cfg.BlockMaxSize < blockMaxSizeMin || cfg.BlockMaxSize > - blockMaxSizeMax { + if cfg.BlockMaxSize < BlockMaxSizeMin || cfg.BlockMaxSize > + BlockMaxSizeMax { str := "%s: The blockmaxsize option must be in between %d " + "and %d -- parsed [%d]" - err := fmt.Errorf(str, funcName, blockMaxSizeMin, - blockMaxSizeMax, cfg.BlockMaxSize) + err := fmt.Errorf(str, funcName, BlockMaxSizeMin, + BlockMaxSizeMax, cfg.BlockMaxSize) fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, usageMessage) return nil, nil, err } // Limit the max block weight to a sane value. - if cfg.BlockMaxWeight < blockMaxWeightMin || - cfg.BlockMaxWeight > blockMaxWeightMax { + if cfg.BlockMaxWeight < BlockMaxWeightMin || + cfg.BlockMaxWeight > BlockMaxWeightMax { str := "%s: The blockmaxweight option must be in between %d " + "and %d -- parsed [%d]" - err := fmt.Errorf(str, funcName, blockMaxWeightMin, - blockMaxWeightMax, cfg.BlockMaxWeight) + err := fmt.Errorf(str, funcName, BlockMaxWeightMin, + BlockMaxWeightMax, cfg.BlockMaxWeight) fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, usageMessage) return nil, nil, err @@ -873,15 +926,15 @@ func loadConfig() (*config, []string, error) { // 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. - case cfg.BlockMaxSize == defaultBlockMaxSize && - cfg.BlockMaxWeight != defaultBlockMaxWeight: + case cfg.BlockMaxSize == DefaultBlockMaxSize && + cfg.BlockMaxWeight != DefaultBlockMaxWeight: cfg.BlockMaxSize = blockchain.MaxBlockBaseSize - 1000 // 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. - case cfg.BlockMaxSize != defaultBlockMaxSize && - cfg.BlockMaxWeight == defaultBlockMaxWeight: + case cfg.BlockMaxSize != DefaultBlockMaxSize && + cfg.BlockMaxWeight == DefaultBlockMaxWeight: cfg.BlockMaxWeight = cfg.BlockMaxSize * blockchain.WitnessScaleFactor } @@ -931,9 +984,9 @@ func loadConfig() (*config, []string, error) { } // Check mining addresses are valid and saved parsed versions. - cfg.miningAddrs = make([]btcutil.Address, 0, len(cfg.MiningAddrs)) + cfg.Config.MiningAddrs = make([]btcutil.Address, 0, len(cfg.MiningAddrs)) for _, strAddr := range cfg.MiningAddrs { - addr, err := btcutil.DecodeAddress(strAddr, activeNetParams.Params) + addr, err := btcutil.DecodeAddress(strAddr, params.ActiveNetParams.Params) if err != nil { str := "%s: mining address '%s' failed to decode: %v" err := fmt.Errorf(str, funcName, strAddr, err) @@ -941,14 +994,14 @@ func loadConfig() (*config, []string, error) { fmt.Fprintln(os.Stderr, usageMessage) return nil, nil, err } - if !addr.IsForNet(activeNetParams.Params) { + if !addr.IsForNet(params.ActiveNetParams.Params) { str := "%s: mining address '%s' is on the wrong network" err := fmt.Errorf(str, funcName, strAddr) fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, usageMessage) return nil, nil, err } - cfg.miningAddrs = append(cfg.miningAddrs, addr) + cfg.Config.MiningAddrs = append(cfg.Config.MiningAddrs, addr) } // Ensure there is at least one mining address when the generate flag is @@ -965,12 +1018,12 @@ func loadConfig() (*config, []string, error) { // Add default port to all listener addresses if needed and remove // duplicate addresses. cfg.Listeners = normalizeAddresses(cfg.Listeners, - activeNetParams.DefaultPort) + params.ActiveNetParams.DefaultPort) // Add default port to all rpc listener addresses if needed and remove // duplicate addresses. cfg.RPCListeners = normalizeAddresses(cfg.RPCListeners, - activeNetParams.rpcPort) + params.ActiveNetParams.RPCPort) // Only allow TLS to be disabled if the RPC is bound to localhost // addresses. @@ -1005,9 +1058,9 @@ func loadConfig() (*config, []string, error) { // Add default port to all added peer addresses if needed and remove // duplicate addresses. cfg.AddPeers = normalizeAddresses(cfg.AddPeers, - activeNetParams.DefaultPort) + params.ActiveNetParams.DefaultPort) cfg.ConnectPeers = normalizeAddresses(cfg.ConnectPeers, - activeNetParams.DefaultPort) + params.ActiveNetParams.DefaultPort) // --noonion and --onion do not mix. if cfg.NoOnion && cfg.OnionProxy != "" { @@ -1019,7 +1072,7 @@ func loadConfig() (*config, []string, error) { } // Check the checkpoints for syntax errors. - cfg.addCheckpoints, err = parseCheckpoints(cfg.AddCheckpoints) + cfg.Config.AddCheckpoints, err = parseCheckpoints(cfg.AddCheckpoints) if err != nil { str := "%s: Error parsing checkpoints: %v" err := fmt.Errorf(str, funcName, err) @@ -1142,9 +1195,9 @@ func loadConfig() (*config, []string, error) { } } - if cfg.Prune != 0 && cfg.Prune < pruneMinSize { + if cfg.Prune != 0 && cfg.Prune < PruneMinSize { err := fmt.Errorf("%s: the minimum value for --prune is %d. Got %d", - funcName, pruneMinSize, cfg.Prune) + funcName, PruneMinSize, cfg.Prune) fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, usageMessage) return nil, nil, err @@ -1170,10 +1223,10 @@ func loadConfig() (*config, []string, error) { // done. This prevents the warning on help messages and invalid // options. Note this should go directly before the return. if configFileError != nil { - btcdLog.Warnf("%v", configFileError) + log.BtcdLog.Warnf("%v", configFileError) } - return &cfg, remainingArgs, nil + return &cfg.Config, remainingArgs, nil } // createDefaultConfig copies the file sample-btcd.conf to the given destination path, @@ -1190,7 +1243,7 @@ func createDefaultConfigFile(destinationPath string) error { if err != nil { return err } - sampleConfigPath := filepath.Join(path, sampleConfigFilename) + sampleConfigPath := filepath.Join(path, SampleConfigFilename) // We generate a random user and password randomBytes := make([]byte, 20) @@ -1242,31 +1295,3 @@ func createDefaultConfigFile(destinationPath string) error { return nil } - -// btcdDial connects to the address on the named network using the appropriate -// dial function depending on the address and configuration options. For -// example, .onion addresses will be dialed using the onion specific proxy if -// one was specified, but will otherwise use the normal dial function (which -// could itself use a proxy or not). -func btcdDial(addr net.Addr) (net.Conn, error) { - if strings.Contains(addr.String(), ".onion:") { - return cfg.oniondial(addr.Network(), addr.String(), - defaultConnectTimeout) - } - return cfg.dial(addr.Network(), addr.String(), defaultConnectTimeout) -} - -// btcdLookup resolves the IP of the given host using the correct DNS lookup -// function depending on the configuration options. For example, addresses will -// be resolved using tor when the --proxy flag was specified unless --noonion -// was also specified in which case the normal system DNS resolver will be used. -// -// Any attempt to resolve a tor address (.onion) will return an error since they -// are not intended to be resolved outside of the tor proxy. -func btcdLookup(host string) ([]net.IP, error) { - if strings.HasSuffix(host, ".onion") { - return nil, fmt.Errorf("attempt to resolve tor address %s", host) - } - - return cfg.lookup(host) -} diff --git a/config_test.go b/internal/config/config_test.go similarity index 94% rename from config_test.go rename to internal/config/config_test.go index 42a0cd4b90..7b4d6e28b7 100644 --- a/config_test.go +++ b/internal/config/config_test.go @@ -1,4 +1,4 @@ -package main +package config import ( "os" @@ -19,7 +19,7 @@ func TestCreateDefaultConfigFile(t *testing.T) { if !ok { t.Fatalf("Failed finding config file path") } - sampleConfigFile := filepath.Join(filepath.Dir(path), "sample-btcd.conf") + sampleConfigFile := filepath.Join(filepath.Dir(path), "../..", "sample-btcd.conf") // Setup a temporary directory tmpDir, err := os.MkdirTemp("", "btcd") diff --git a/log.go b/internal/log/log.go similarity index 71% rename from log.go rename to internal/log/log.go index 5707d7c23a..9d82cc95f5 100644 --- a/log.go +++ b/internal/log/log.go @@ -3,7 +3,7 @@ // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package main +package log import ( "fmt" @@ -32,7 +32,7 @@ type logWriter struct{} func (logWriter) Write(p []byte) (n int, err error) { os.Stdout.Write(p) - logRotator.Write(p) + LogRotator.Write(p) return len(p), nil } @@ -50,65 +50,65 @@ var ( // or data races and/or nil pointer dereferences will occur. backendLog = btclog.NewBackend(logWriter{}) - // logRotator is one of the logging outputs. It should be closed on + // LogRotator is one of the logging outputs. It should be closed on // application shutdown. - logRotator *rotator.Rotator + LogRotator *rotator.Rotator adxrLog = backendLog.Logger("ADXR") - amgrLog = backendLog.Logger("AMGR") + AmgrLog = backendLog.Logger("AMGR") cmgrLog = backendLog.Logger("CMGR") bcdbLog = backendLog.Logger("BCDB") - btcdLog = backendLog.Logger("BTCD") + BtcdLog = backendLog.Logger("BTCD") chanLog = backendLog.Logger("CHAN") discLog = backendLog.Logger("DISC") - indxLog = backendLog.Logger("INDX") + IndxLog = backendLog.Logger("INDX") minrLog = backendLog.Logger("MINR") - peerLog = backendLog.Logger("PEER") - rpcsLog = backendLog.Logger("RPCS") + PeerLog = backendLog.Logger("PEER") + RpcsLog = backendLog.Logger("RPCS") scrpLog = backendLog.Logger("SCRP") - srvrLog = backendLog.Logger("SRVR") + SrvrLog = backendLog.Logger("SRVR") syncLog = backendLog.Logger("SYNC") - txmpLog = backendLog.Logger("TXMP") + TxmpLog = backendLog.Logger("TXMP") ) // Initialize package-global logger variables. func init() { - addrmgr.UseLogger(amgrLog) + addrmgr.UseLogger(AmgrLog) connmgr.UseLogger(cmgrLog) database.UseLogger(bcdbLog) blockchain.UseLogger(chanLog) - indexers.UseLogger(indxLog) + indexers.UseLogger(IndxLog) mining.UseLogger(minrLog) cpuminer.UseLogger(minrLog) - peer.UseLogger(peerLog) + peer.UseLogger(PeerLog) txscript.UseLogger(scrpLog) netsync.UseLogger(syncLog) - mempool.UseLogger(txmpLog) + mempool.UseLogger(TxmpLog) } -// subsystemLoggers maps each subsystem identifier to its associated logger. -var subsystemLoggers = map[string]btclog.Logger{ +// SubsystemLoggers maps each subsystem identifier to its associated logger. +var SubsystemLoggers = map[string]btclog.Logger{ "ADXR": adxrLog, - "AMGR": amgrLog, + "AMGR": AmgrLog, "CMGR": cmgrLog, "BCDB": bcdbLog, - "BTCD": btcdLog, + "BTCD": BtcdLog, "CHAN": chanLog, "DISC": discLog, - "INDX": indxLog, + "INDX": IndxLog, "MINR": minrLog, - "PEER": peerLog, - "RPCS": rpcsLog, + "PEER": PeerLog, + "RPCS": RpcsLog, "SCRP": scrpLog, - "SRVR": srvrLog, + "SRVR": SrvrLog, "SYNC": syncLog, - "TXMP": txmpLog, + "TXMP": TxmpLog, } -// initLogRotator initializes the logging rotater to write logs to logFile and +// InitLogRotator initializes the logging rotater to write logs to logFile and // create roll files in the same directory. It must be called before the // package-global log rotater variables are used. -func initLogRotator(logFile string) { +func InitLogRotator(logFile string) { logDir, _ := filepath.Split(logFile) err := os.MkdirAll(logDir, 0700) if err != nil { @@ -121,15 +121,15 @@ func initLogRotator(logFile string) { os.Exit(1) } - logRotator = r + LogRotator = r } -// setLogLevel sets the logging level for provided subsystem. Invalid +// SetLogLevel sets the logging level for provided subsystem. Invalid // subsystems are ignored. Uninitialized subsystems are dynamically created as // needed. -func setLogLevel(subsystemID string, logLevel string) { +func SetLogLevel(subsystemID string, logLevel string) { // Ignore invalid subsystems. - logger, ok := subsystemLoggers[subsystemID] + logger, ok := SubsystemLoggers[subsystemID] if !ok { return } @@ -139,29 +139,29 @@ func setLogLevel(subsystemID string, logLevel string) { logger.SetLevel(level) } -// setLogLevels sets the log level for all subsystem loggers to the passed +// SetLogLevels sets the log level for all subsystem loggers to the passed // level. It also dynamically creates the subsystem loggers as needed, so it // can be used to initialize the logging system. -func setLogLevels(logLevel string) { +func SetLogLevels(logLevel string) { // Configure all sub-systems with the new logging level. Dynamically // create loggers as needed. - for subsystemID := range subsystemLoggers { - setLogLevel(subsystemID, logLevel) + for subsystemID := range SubsystemLoggers { + SetLogLevel(subsystemID, logLevel) } } -// directionString is a helper function that returns a string that represents +// DirectionString is a helper function that returns a string that represents // the direction of a connection (inbound or outbound). -func directionString(inbound bool) string { +func DirectionString(inbound bool) string { if inbound { return "inbound" } return "outbound" } -// pickNoun returns the singular or plural form of a noun depending +// PickNoun returns the singular or plural form of a noun depending // on the count n. -func pickNoun(n uint64, singular, plural string) string { +func PickNoun(n uint64, singular, plural string) string { if n == 1 { return singular } diff --git a/params.go b/internal/params/params.go similarity index 71% rename from params.go rename to internal/params/params.go index b4d1453dfb..f1873d5560 100644 --- a/params.go +++ b/internal/params/params.go @@ -2,67 +2,67 @@ // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package main +package params import ( "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/wire" ) -// activeNetParams is a pointer to the parameters specific to the +// ActiveNetParams is a pointer to the parameters specific to the // currently active bitcoin network. -var activeNetParams = &mainNetParams +var ActiveNetParams = &MainNetParams // params is used to group parameters for various networks such as the main // network and test networks. type params struct { *chaincfg.Params - rpcPort string + RPCPort string } -// mainNetParams contains parameters specific to the main network +// MainNetParams contains parameters specific to the main network // (wire.MainNet). NOTE: The RPC port is intentionally different than the // reference implementation because btcd does not handle wallet requests. The // separate wallet process listens on the well-known port and forwards requests // it does not handle on to btcd. This approach allows the wallet process // to emulate the full reference implementation RPC API. -var mainNetParams = params{ +var MainNetParams = params{ Params: &chaincfg.MainNetParams, - rpcPort: "8334", + RPCPort: "8334", } -// regressionNetParams contains parameters specific to the regression test +// RegressionNetParams contains parameters specific to the regression test // network (wire.TestNet). NOTE: The RPC port is intentionally different // than the reference implementation - see the mainNetParams comment for // details. -var regressionNetParams = params{ +var RegressionNetParams = params{ Params: &chaincfg.RegressionNetParams, - rpcPort: "18334", + RPCPort: "18334", } -// testNet3Params contains parameters specific to the test network (version 3) +// TestNet3Params contains parameters specific to the test network (version 3) // (wire.TestNet3). NOTE: The RPC port is intentionally different than the // reference implementation - see the mainNetParams comment for details. -var testNet3Params = params{ +var TestNet3Params = params{ Params: &chaincfg.TestNet3Params, - rpcPort: "18334", + RPCPort: "18334", } -// simNetParams contains parameters specific to the simulation test network +// SimNetParams contains parameters specific to the simulation test network // (wire.SimNet). -var simNetParams = params{ +var SimNetParams = params{ Params: &chaincfg.SimNetParams, - rpcPort: "18556", + RPCPort: "18556", } -// sigNetParams contains parameters specific to the Signet network +// SigNetParams contains parameters specific to the Signet network // (wire.SigNet). -var sigNetParams = params{ +var SigNetParams = params{ Params: &chaincfg.SigNetParams, - rpcPort: "38332", + RPCPort: "38332", } -// netName returns the name used when referring to a bitcoin network. At the +// NetName returns the name used when referring to a bitcoin network. At the // time of writing, btcd currently places blocks for testnet version 3 in the // data and log directory "testnet", which does not match the Name field of the // chaincfg parameters. This function can be used to override this directory @@ -71,7 +71,7 @@ var sigNetParams = params{ // A proper upgrade to move the data and log directories for this network to // "testnet3" is planned for the future, at which point this function can be // removed and the network parameter's name used instead. -func netName(chainParams *params) string { +func NetName(chainParams *params) string { switch chainParams.Net { case wire.TestNet3: return "testnet" diff --git a/mining/cpuminer/cpuminer.go b/mining/cpuminer/cpuminer.go index 2c07f2ee1f..bd3a5feeb9 100644 --- a/mining/cpuminer/cpuminer.go +++ b/mining/cpuminer/cpuminer.go @@ -104,6 +104,7 @@ type CPUMiner struct { updateHashes chan uint64 speedMonitorQuit chan struct{} quit chan struct{} + MiningAddrs []btcutil.Address } // speedMonitor handles tracking the number of hashes per second the mining @@ -336,7 +337,7 @@ out: // Choose a payment address at random. rand.Seed(time.Now().UnixNano()) - payToAddr := m.cfg.MiningAddrs[rand.Intn(len(m.cfg.MiningAddrs))] + payToAddr := m.MiningAddrs[rand.Intn(len(m.MiningAddrs))] // Create a new block template using the available transactions // in the memory pool as a source of transactions to potentially @@ -590,7 +591,7 @@ func (m *CPUMiner) GenerateNBlocks(n uint32) ([]*chainhash.Hash, error) { // Choose a payment address at random. rand.Seed(time.Now().UnixNano()) - payToAddr := m.cfg.MiningAddrs[rand.Intn(len(m.cfg.MiningAddrs))] + payToAddr := m.MiningAddrs[rand.Intn(len(m.MiningAddrs))] // Create a new block template using the available transactions // in the memory pool as a source of transactions to potentially @@ -638,5 +639,6 @@ func New(cfg *Config) *CPUMiner { updateNumWorkers: make(chan struct{}), queryHashesPerSec: make(chan float64), updateHashes: make(chan uint64), + MiningAddrs: cfg.MiningAddrs, } } diff --git a/rpcserver.go b/rpcserver.go index 363661d787..34c743ac46 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -35,6 +35,9 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/database" + "github.com/btcsuite/btcd/internal/config" + "github.com/btcsuite/btcd/internal/log" + "github.com/btcsuite/btcd/internal/params" "github.com/btcsuite/btcd/mempool" "github.com/btcsuite/btcd/mining" "github.com/btcsuite/btcd/mining/cpuminer" @@ -141,6 +144,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{ "decodescript": handleDecodeScript, "estimatefee": handleEstimateFee, "generate": handleGenerate, + "generatetoaddress": handleGenerateToAddress, "getaddednodeinfo": handleGetAddedNodeInfo, "getbestblock": handleGetBestBlock, "getbestblockhash": handleGetBestBlockHash, @@ -377,7 +381,7 @@ func handleAskWallet(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) ( func handleAddNode(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { c := cmd.(*btcjson.AddNodeCmd) - addr := normalizeAddress(c.Addr, s.cfg.ChainParams.DefaultPort) + addr := config.NormalizeAddress(c.Addr, s.cfg.ChainParams.DefaultPort) var err error switch c.SubCmd { case "add": @@ -421,7 +425,7 @@ func handleNode(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (inter err = s.cfg.ConnMgr.DisconnectByID(int32(nodeID)) } else { if _, _, errP := net.SplitHostPort(c.Target); errP == nil || net.ParseIP(c.Target) != nil { - addr = normalizeAddress(c.Target, params.DefaultPort) + addr = config.NormalizeAddress(c.Target, params.DefaultPort) err = s.cfg.ConnMgr.DisconnectByAddr(addr) } else { return nil, &btcjson.RPCError{ @@ -446,7 +450,7 @@ func handleNode(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (inter err = s.cfg.ConnMgr.RemoveByID(int32(nodeID)) } else { if _, _, errP := net.SplitHostPort(c.Target); errP == nil || net.ParseIP(c.Target) != nil { - addr = normalizeAddress(c.Target, params.DefaultPort) + addr = config.NormalizeAddress(c.Target, params.DefaultPort) err = s.cfg.ConnMgr.RemoveByAddr(addr) } else { return nil, &btcjson.RPCError{ @@ -463,7 +467,7 @@ func handleNode(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (inter } case "connect": - addr = normalizeAddress(c.Target, params.DefaultPort) + addr = config.NormalizeAddress(c.Target, params.DefaultPort) // Default to temporary connections. subCmd := "temp" @@ -634,10 +638,10 @@ func handleDebugLevel(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) // Special show command to list supported subsystems. if c.LevelSpec == "show" { return fmt.Sprintf("Supported subsystems %v", - supportedSubsystems()), nil + config.SupportedSubsystems()), nil } - err := parseAndSetDebugLevels(c.LevelSpec) + err := config.ParseAndSetDebugLevels(c.LevelSpec) if err != nil { return nil, &btcjson.RPCError{ Code: btcjson.ErrRPCInvalidParams.Code, @@ -888,11 +892,10 @@ func handleEstimateFee(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) return float64(feeRate), nil } -// handleGenerate handles generate commands. -func handleGenerate(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { +func generate(s *rpcServer, blocks uint32) ([]string, error) { // Respond with an error if there are no addresses to pay the // created blocks to. - if len(cfg.miningAddrs) == 0 { + if len(cfg.MiningAddrs) == 0 { return nil, &btcjson.RPCError{ Code: btcjson.ErrRPCInternal.Code, Message: "No payment addresses specified " + @@ -912,10 +915,8 @@ func handleGenerate(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i } } - c := cmd.(*btcjson.GenerateCmd) - // Respond with an error if the client is requesting 0 blocks to be generated. - if c.NumBlocks == 0 { + if blocks == 0 { return nil, &btcjson.RPCError{ Code: btcjson.ErrRPCInternal.Code, Message: "Please request a nonzero number of blocks to generate.", @@ -923,9 +924,9 @@ func handleGenerate(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i } // Create a reply - reply := make([]string, c.NumBlocks) + reply := make([]string, blocks) - blockHashes, err := s.cfg.CPUMiner.GenerateNBlocks(c.NumBlocks) + blockHashes, err := s.cfg.CPUMiner.GenerateNBlocks(blocks) if err != nil { return nil, &btcjson.RPCError{ Code: btcjson.ErrRPCInternal.Code, @@ -942,6 +943,31 @@ func handleGenerate(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i return reply, nil } +func handleGenerateToAddress(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { + c := cmd.(*btcjson.GenerateToAddressCmd) + + addr, err := btcutil.DecodeAddress(c.Address, params.ActiveNetParams.Params) + if err != nil { + return nil, err + } + + before := s.cfg.CPUMiner.MiningAddrs[:] + s.cfg.CPUMiner.MiningAddrs = []btcutil.Address{addr} + + reply, err := generate(s, uint32(c.NumBlocks)) + + s.cfg.CPUMiner.MiningAddrs = before + + return reply, err +} + +// handleGenerate handles generate commands. +func handleGenerate(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { + c := cmd.(*btcjson.GenerateCmd) + + return generate(s, c.NumBlocks) +} + // handleGetAddedNodeInfo handles getaddednodeinfo commands. func handleGetAddedNodeInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { c := cmd.(*btcjson.GetAddedNodeInfoCmd) @@ -1003,7 +1029,7 @@ func handleGetAddedNodeInfo(s *rpcServer, cmd interface{}, closeChan <-chan stru default: // Do a DNS lookup for the address. If the lookup fails, just // use the host. - ips, err := btcdLookup(host) + ips, err := cfg.Lookup(host) if err != nil { ipList = make([]string, 1) ipList[0] = host @@ -1022,7 +1048,7 @@ func handleGetAddedNodeInfo(s *rpcServer, cmd interface{}, closeChan <-chan stru addr.Address = ip addr.Connected = "false" if ip == host && peer.Connected() { - addr.Connected = directionString(peer.Inbound()) + addr.Connected = log.DirectionString(peer.Inbound()) } addrs = append(addrs, addr) } @@ -1588,7 +1614,7 @@ func (state *gbtWorkState) updateBlockTemplate(s *rpcServer, useCoinbaseValue bo // to create their own coinbase. var payAddr btcutil.Address if !useCoinbaseValue { - payAddr = cfg.miningAddrs[rand.Intn(len(cfg.miningAddrs))] + payAddr = cfg.MiningAddrs[rand.Intn(len(cfg.MiningAddrs))] } // Create a new block template that has a coinbase which anyone @@ -1643,7 +1669,7 @@ func (state *gbtWorkState) updateBlockTemplate(s *rpcServer, useCoinbaseValue bo // returned if none have been specified. if !useCoinbaseValue && !template.ValidPayAddress { // Choose a payment address at random. - payToAddr := cfg.miningAddrs[rand.Intn(len(cfg.miningAddrs))] + payToAddr := cfg.MiningAddrs[rand.Intn(len(cfg.MiningAddrs))] // Update the block coinbase output of the template to // pay to the randomly selected payment address. @@ -1952,7 +1978,7 @@ func handleGetBlockTemplateRequest(s *rpcServer, request *btcjson.TemplateReques // When a coinbase transaction has been requested, respond with an error // if there are no addresses to pay the created block template to. - if !useCoinbaseValue && len(cfg.miningAddrs) == 0 { + if !useCoinbaseValue && len(cfg.MiningAddrs) == 0 { return nil, &btcjson.RPCError{ Code: btcjson.ErrRPCInternal.Code, Message: "A coinbase transaction has been requested, " + @@ -2360,7 +2386,7 @@ func handleGetInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (in Proxy: cfg.Proxy, Difficulty: getDifficultyRatio(best.Bits, s.cfg.ChainParams), TestNet: cfg.TestNet3, - RelayFee: cfg.minRelayTxFee.ToBTC(), + RelayFee: cfg.MinRelayTxFee.ToBTC(), } return ret, nil @@ -3546,7 +3572,7 @@ func handleSetGenerate(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) } else { // Respond with an error if there are no addresses to pay the // created blocks to. - if len(cfg.miningAddrs) == 0 { + if len(cfg.MiningAddrs) == 0 { return nil, &btcjson.RPCError{ Code: btcjson.ErrRPCInternal.Code, Message: "No payment addresses specified " + diff --git a/rpcserverhelp.go b/rpcserverhelp.go index 71f96e99fd..4118fc7c3d 100644 --- a/rpcserverhelp.go +++ b/rpcserverhelp.go @@ -132,6 +132,14 @@ var helpDescsEnUS = map[string]string{ "generate-numblocks": "Number of blocks to generate", "generate--result0": "The hashes, in order, of blocks generated by the call", + // GenerateToAddressCmd help + "generatetoaddress--synopsis": "Generates a set number of blocks (simnet or regtest only), paying the block reward to the specified address and returns a JSON\n" + + " array of their hashes.", + "generatetoaddress-numblocks": "Number of blocks to generate", + "generatetoaddress-address": "The address to send the newly generated bitcoin", + "generatetoaddress-maxtries": "How many iterations to try", + "generatetoaddress--result0": "The hashes, in order, of blocks generated by the call", + // GetAddedNodeInfoResultAddr help. "getaddednodeinforesultaddr-address": "The ip address for this DNS entry", "getaddednodeinforesultaddr-connected": "The connection 'direction' (inbound/outbound/false)", @@ -766,6 +774,7 @@ var rpcResultTypes = map[string][]interface{}{ "decodescript": {(*btcjson.DecodeScriptResult)(nil)}, "estimatefee": {(*float64)(nil)}, "generate": {(*[]string)(nil)}, + "generatetoaddress": {(*[]string)(nil)}, "getaddednodeinfo": {(*[]string)(nil), (*[]btcjson.GetAddedNodeInfoResult)(nil)}, "getbestblock": {(*btcjson.GetBestBlockResult)(nil)}, "getbestblockhash": {(*string)(nil)}, diff --git a/server.go b/server.go index 66794e4bb7..e45ac30be1 100644 --- a/server.go +++ b/server.go @@ -31,6 +31,9 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/connmgr" "github.com/btcsuite/btcd/database" + "github.com/btcsuite/btcd/internal/config" + "github.com/btcsuite/btcd/internal/log" + "github.com/btcsuite/btcd/internal/params" "github.com/btcsuite/btcd/mempool" "github.com/btcsuite/btcd/mining" "github.com/btcsuite/btcd/mining/cpuminer" @@ -360,7 +363,7 @@ func (sp *serverPeer) pushAddrMsg(addresses []*wire.NetAddressV2) { known, err := sp.PushAddrV2Msg(addrs) if err != nil { - peerLog.Errorf("Can't push addrv2 message to %s: %v", + log.PeerLog.Errorf("Can't push addrv2 message to %s: %v", sp.Peer, err) sp.Disconnect() return @@ -1432,14 +1435,14 @@ func (sp *serverPeer) OnNotFound(p *peer.Peer, msg *wire.MsgNotFound) { } } if numBlocks > 0 { - blockStr := pickNoun(uint64(numBlocks), "block", "blocks") + blockStr := log.PickNoun(uint64(numBlocks), "block", "blocks") reason := fmt.Sprintf("%d %v not found", numBlocks, blockStr) if sp.addBanScore(20*numBlocks, 0, reason) { return } } if numTxns > 0 { - txStr := pickNoun(uint64(numTxns), "transaction", "transactions") + txStr := log.PickNoun(uint64(numTxns), "transaction", "transactions") reason := fmt.Sprintf("%d %v not found", numTxns, txStr) if sp.addBanScore(0, 10*numTxns, reason) { return @@ -1859,7 +1862,7 @@ func (s *server) handleBanPeerMsg(state *peerState, sp *serverPeer) { srvrLog.Debugf("can't split ban peer %s %v", sp.Addr(), err) return } - direction := directionString(sp.Inbound()) + direction := log.DirectionString(sp.Inbound()) srvrLog.Infof("Banned peer %s (%s) for %v", host, direction, cfg.BanDuration) state.banned[host] = time.Now().Add(cfg.BanDuration) @@ -2218,7 +2221,7 @@ func (s *server) peerDoneHandler(sp *serverPeer) { numEvicted := s.txMemPool.RemoveOrphansByTag(mempool.Tag(sp.ID())) if numEvicted > 0 { txmpLog.Debugf("Evicted %d %s from peer %v (id %d)", - numEvicted, pickNoun(numEvicted, "orphan", + numEvicted, log.PickNoun(numEvicted, "orphan", "orphans"), sp, sp.ID()) } } @@ -2249,8 +2252,8 @@ func (s *server) peerHandler() { if !cfg.DisableDNSSeed { // Add peers discovered through DNS to the address manager. - connmgr.SeedFromDNS(activeNetParams.Params, defaultRequiredServices, - btcdLookup, func(addrs []*wire.NetAddressV2) { + connmgr.SeedFromDNS(params.ActiveNetParams.Params, defaultRequiredServices, + cfg.Lookup, func(addrs []*wire.NetAddressV2) { // Bitcoind uses a lookup of the dns seeder here. This // is rather strange since the values looked up by the // DNS seed lookups will vary quite a lot. @@ -2618,7 +2621,7 @@ func (s *server) upnpUpdateThread() { // Go off immediately to prevent code duplication, thereafter we renew // lease every 15 minutes. timer := time.NewTimer(0 * time.Second) - lport, _ := strconv.ParseInt(activeNetParams.DefaultPort, 10, 16) + lport, _ := strconv.ParseInt(params.ActiveNetParams.DefaultPort, 10, 16) first := true out: for { @@ -2735,7 +2738,7 @@ func newServer(listenAddrs, agentBlacklist, agentWhitelist []string, services &^= wire.SFNodeNetwork } - amgr := addrmgr.New(cfg.DataDir, btcdLookup) + amgr := addrmgr.New(cfg.DataDir, cfg.Lookup) var listeners []net.Listener var nat NAT @@ -2821,7 +2824,7 @@ func newServer(listenAddrs, agentBlacklist, agentWhitelist []string, // Merge given checkpoints with the default ones unless they are disabled. var checkpoints []chaincfg.Checkpoint if !cfg.DisableCheckpoints { - checkpoints = mergeCheckpoints(s.chainParams.Checkpoints, cfg.addCheckpoints) + checkpoints = mergeCheckpoints(s.chainParams.Checkpoints, cfg.AddCheckpoints) } // Log that the node is pruned. @@ -2883,9 +2886,9 @@ func newServer(listenAddrs, agentBlacklist, agentWhitelist []string, AcceptNonStd: cfg.RelayNonStd, FreeTxRelayLimit: cfg.FreeTxRelayLimit, MaxOrphanTxs: cfg.MaxOrphanTxs, - MaxOrphanTxSize: defaultMaxOrphanTxSize, + MaxOrphanTxSize: config.DefaultMaxOrphanTxSize, MaxSigOpCostPerTx: blockchain.MaxBlockSigOpsCost / 4, - MinRelayTxFee: cfg.minRelayTxFee, + MinRelayTxFee: cfg.MinRelayTxFee, MaxTxVersion: 2, RejectReplacement: cfg.RejectReplacement, }, @@ -2928,7 +2931,7 @@ func newServer(listenAddrs, agentBlacklist, agentWhitelist []string, BlockMinSize: cfg.BlockMinSize, BlockMaxSize: cfg.BlockMaxSize, BlockPrioritySize: cfg.BlockPrioritySize, - TxMinFreeFee: cfg.minRelayTxFee, + TxMinFreeFee: cfg.MinRelayTxFee, } blockTemplateGenerator := mining.NewBlkTmplGenerator(&policy, s.chainParams, s.txMemPool, s.chain, s.timeSource, @@ -2936,7 +2939,7 @@ func newServer(listenAddrs, agentBlacklist, agentWhitelist []string, s.cpuMiner = cpuminer.New(&cpuminer.Config{ ChainParams: chainParams, BlockTemplateGenerator: blockTemplateGenerator, - MiningAddrs: cfg.miningAddrs, + MiningAddrs: cfg.MiningAddrs, ProcessBlock: s.syncManager.ProcessBlock, ConnectedCount: s.ConnectedCount, IsCurrent: s.syncManager.IsCurrent, @@ -2976,7 +2979,7 @@ func newServer(listenAddrs, agentBlacklist, agentWhitelist []string, // allow nondefault ports after 50 failed tries. if tries < 50 && fmt.Sprintf("%d", addr.NetAddress().Port) != - activeNetParams.DefaultPort { + params.ActiveNetParams.DefaultPort { continue } @@ -3001,7 +3004,7 @@ func newServer(listenAddrs, agentBlacklist, agentWhitelist []string, OnAccept: s.inboundPeerConnected, RetryDuration: connectionRetryInterval, TargetOutbound: uint32(targetOutbound), - Dial: btcdDial, + Dial: cfg.Dial, OnConnection: s.outboundPeerConnected, GetNewAddress: newAddressFunc, }) @@ -3091,10 +3094,10 @@ func initListeners(amgr *addrmgr.AddrManager, listenAddrs []string, services wir var nat NAT if len(cfg.ExternalIPs) != 0 { - defaultPort, err := strconv.ParseUint(activeNetParams.DefaultPort, 10, 16) + defaultPort, err := strconv.ParseUint(params.ActiveNetParams.DefaultPort, 10, 16) if err != nil { srvrLog.Errorf("Can not parse default port %s for active chain: %v", - activeNetParams.DefaultPort, err) + params.ActiveNetParams.DefaultPort, err) return nil, nil, err } @@ -3181,7 +3184,7 @@ func addrStringToNetAddr(addr string) (net.Addr, error) { } // Attempt to look up an IP address associated with the parsed host. - ips, err := btcdLookup(host) + ips, err := cfg.Lookup(host) if err != nil { return nil, err } @@ -3268,7 +3271,7 @@ func dynamicTickDuration(remaining time.Duration) time.Duration { // isWhitelisted returns whether the IP address is included in the whitelisted // networks and IPs. func isWhitelisted(addr net.Addr) bool { - if len(cfg.whitelists) == 0 { + if len(cfg.Whitelists) == 0 { return false } @@ -3283,7 +3286,7 @@ func isWhitelisted(addr net.Addr) bool { return false } - for _, ipnet := range cfg.whitelists { + for _, ipnet := range cfg.Whitelists { if ipnet.Contains(ip) { return true } diff --git a/upgrade.go b/upgrade.go index 5dec8d4c6a..bd817ef981 100644 --- a/upgrade.go +++ b/upgrade.go @@ -8,6 +8,8 @@ import ( "io" "os" "path/filepath" + + "github.com/btcsuite/btcd/internal/config" ) // dirEmpty returns whether or not the specified directory path is empty. @@ -109,7 +111,7 @@ func upgradeDBPaths() error { func upgradeDataPaths() error { // No need to migrate if the old and new home paths are the same. oldHomePath := oldBtcdHomeDir() - newHomePath := defaultHomeDir + newHomePath := config.DefaultHomeDir if oldHomePath == newHomePath { return nil } @@ -125,8 +127,8 @@ func upgradeDataPaths() error { } // Move old btcd.conf into new location if needed. - oldConfPath := filepath.Join(oldHomePath, defaultConfigFilename) - newConfPath := filepath.Join(newHomePath, defaultConfigFilename) + oldConfPath := filepath.Join(oldHomePath, config.DefaultConfigFilename) + newConfPath := filepath.Join(newHomePath, config.DefaultConfigFilename) if fileExists(oldConfPath) && !fileExists(newConfPath) { err := os.Rename(oldConfPath, newConfPath) if err != nil { @@ -135,8 +137,8 @@ func upgradeDataPaths() error { } // Move old data directory into new location if needed. - oldDataPath := filepath.Join(oldHomePath, defaultDataDirname) - newDataPath := filepath.Join(newHomePath, defaultDataDirname) + oldDataPath := filepath.Join(oldHomePath, config.DefaultDataDirname) + newDataPath := filepath.Join(newHomePath, config.DefaultDataDirname) if fileExists(oldDataPath) && !fileExists(newDataPath) { err := os.Rename(oldDataPath, newDataPath) if err != nil {