diff --git a/config.go b/config.go index 50029774..c45a11dd 100644 --- a/config.go +++ b/config.go @@ -133,11 +133,12 @@ type btcdConfig struct { } type bitcoindConfig struct { - Dir string `long:"dir" description:"The base directory that contains the node's data, logs, configuration file, etc."` - RPCHost string `long:"rpchost" description:"The daemon's rpc listening address. If a port is omitted, then the default port for the selected chain parameters will be used."` - RPCUser string `long:"rpcuser" description:"Username for RPC connections"` - RPCPass string `long:"rpcpass" default-mask:"-" description:"Password for RPC connections"` - ZMQPath string `long:"zmqpath" description:"The path to the ZMQ socket providing at least raw blocks. Raw transactions can be handled as well."` + Dir string `long:"dir" description:"The base directory that contains the node's data, logs, configuration file, etc."` + RPCHost string `long:"rpchost" description:"The daemon's rpc listening address. If a port is omitted, then the default port for the selected chain parameters will be used."` + RPCUser string `long:"rpcuser" description:"Username for RPC connections"` + RPCPass string `long:"rpcpass" default-mask:"-" description:"Password for RPC connections"` + ZMQPubRawBlock string `long:"zmqpubrawblock" description:"The address listening for ZMQ connections to deliver raw block notifications"` + ZMQPubRawTx string `long:"zmqpubrawtx" description:"The address listening for ZMQ connections to deliver raw transaction notifications"` } type autoPilotConfig struct { @@ -1057,8 +1058,12 @@ func parseRPCParams(cConfig *chainConfig, nodeConfig interface{}, net chainCode, switch net { case bitcoinChain: daemonName = "btcd" + confDir = conf.Dir + confFile = "btcd" case litecoinChain: daemonName = "ltcd" + confDir = conf.Dir + confFile = "ltcd" } // If only ONE of RPCUser or RPCPass is set, we assume the @@ -1068,18 +1073,11 @@ func parseRPCParams(cConfig *chainConfig, nodeConfig interface{}, net chainCode, "%[1]v.rpcuser, %[1]v.rpcpass", daemonName) } - switch net { - case bitcoinChain: - confDir = conf.Dir - confFile = "btcd" - case litecoinChain: - confDir = conf.Dir - confFile = "ltcd" - } case *bitcoindConfig: - // If all of RPCUser, RPCPass, and ZMQPath are set, we assume - // those parameters are good to use. - if conf.RPCUser != "" && conf.RPCPass != "" && conf.ZMQPath != "" { + // If all of RPCUser, RPCPass, ZMQBlockHost, and ZMQTxHost are + // set, we assume those parameters are good to use. + if conf.RPCUser != "" && conf.RPCPass != "" && + conf.ZMQPubRawBlock != "" && conf.ZMQPubRawTx != "" { return nil } @@ -1087,25 +1085,24 @@ func parseRPCParams(cConfig *chainConfig, nodeConfig interface{}, net chainCode, switch net { case bitcoinChain: daemonName = "bitcoind" - case litecoinChain: - daemonName = "litecoind" - } - // If only one or two of the parameters are set, we assume the - // user did that unintentionally. - if conf.RPCUser != "" || conf.RPCPass != "" || conf.ZMQPath != "" { - return fmt.Errorf("please set all or none of "+ - "%[1]v.rpcuser, %[1]v.rpcpass, "+ - "and %[1]v.zmqpath", daemonName) - } - - switch net { - case bitcoinChain: confDir = conf.Dir confFile = "bitcoin" case litecoinChain: + daemonName = "litecoind" confDir = conf.Dir confFile = "litecoin" } + + // If only one or two of the parameters are set, we assume the + // user did that unintentionally. + if conf.RPCUser != "" || conf.RPCPass != "" || + conf.ZMQPubRawBlock != "" || conf.ZMQPubRawTx != "" { + + return fmt.Errorf("please set all or none of "+ + "%[1]v.rpcuser, %[1]v.rpcpass, "+ + "%[1]v.zmqpubrawblock, %[1]v.zmqpubrawtx", + daemonName) + } } // If we're in simnet mode, then the running btcd instance won't read @@ -1132,13 +1129,15 @@ func parseRPCParams(cConfig *chainConfig, nodeConfig interface{}, net chainCode, nConf.RPCUser, nConf.RPCPass = rpcUser, rpcPass case "bitcoind", "litecoind": nConf := nodeConfig.(*bitcoindConfig) - rpcUser, rpcPass, zmqPath, err := extractBitcoindRPCParams(confFile) + rpcUser, rpcPass, zmqBlockHost, zmqTxHost, err := + extractBitcoindRPCParams(confFile) if err != nil { return fmt.Errorf("unable to extract RPC credentials:"+ " %v, cannot start w/o RPC connection", err) } - nConf.RPCUser, nConf.RPCPass, nConf.ZMQPath = rpcUser, rpcPass, zmqPath + nConf.RPCUser, nConf.RPCPass = rpcUser, rpcPass + nConf.ZMQPubRawBlock, nConf.ZMQPubRawTx = zmqBlockHost, zmqTxHost } fmt.Printf("Automatically obtained %v's RPC credentials\n", daemonName) @@ -1196,13 +1195,12 @@ func extractBtcdRPCParams(btcdConfigPath string) (string, string, error) { // location of bitcoind's bitcoin.conf on the target system. The routine looks // for a cookie first, optionally following the datadir configuration option in // the bitcoin.conf. If it doesn't find one, it looks for rpcuser/rpcpassword. -func extractBitcoindRPCParams(bitcoindConfigPath string) (string, string, string, error) { - +func extractBitcoindRPCParams(bitcoindConfigPath string) (string, string, string, string, error) { // First, we'll open up the bitcoind configuration file found at the // target destination. bitcoindConfigFile, err := os.Open(bitcoindConfigPath) if err != nil { - return "", "", "", err + return "", "", "", "", err } defer bitcoindConfigFile.Close() @@ -1210,18 +1208,36 @@ func extractBitcoindRPCParams(bitcoindConfigPath string) (string, string, string // we can attempt to locate the RPC credentials. configContents, err := ioutil.ReadAll(bitcoindConfigFile) if err != nil { - return "", "", "", err + return "", "", "", "", err } - // First, we look for the ZMQ path for raw blocks. If raw transactions - // are sent over this interface, we can also get unconfirmed txs. - zmqPathRE, err := regexp.Compile(`(?m)^\s*zmqpubrawblock\s*=\s*([^\s]+)`) + // First, we'll look for the ZMQ hosts providing raw block and raw + // transaction notifications. + zmqBlockHostRE, err := regexp.Compile( + `(?m)^\s*zmqpubrawblock\s*=\s*([^\s]+)`, + ) if err != nil { - return "", "", "", err + return "", "", "", "", err } - zmqPathSubmatches := zmqPathRE.FindSubmatch(configContents) - if len(zmqPathSubmatches) < 2 { - return "", "", "", fmt.Errorf("unable to find zmqpubrawblock in config") + zmqBlockHostSubmatches := zmqBlockHostRE.FindSubmatch(configContents) + if len(zmqBlockHostSubmatches) < 2 { + return "", "", "", "", fmt.Errorf("unable to find " + + "zmqpubrawblock in config") + } + zmqTxHostRE, err := regexp.Compile(`(?m)^\s*zmqpubrawtx\s*=\s*([^\s]+)`) + if err != nil { + return "", "", "", "", err + } + zmqTxHostSubmatches := zmqTxHostRE.FindSubmatch(configContents) + if len(zmqTxHostSubmatches) < 2 { + return "", "", "", "", errors.New("unable to find zmqpubrawtx " + + "in config") + } + zmqBlockHost := string(zmqBlockHostSubmatches[1]) + zmqTxHost := string(zmqTxHostSubmatches[1]) + if zmqBlockHost == zmqTxHost { + return "", "", "", "", errors.New("zmqpubrawblock and " + + "zmqpubrawtx must be different") } // Next, we'll try to find an auth cookie. We need to detect the chain @@ -1229,7 +1245,7 @@ func extractBitcoindRPCParams(bitcoindConfigPath string) (string, string, string dataDir := path.Dir(bitcoindConfigPath) dataDirRE, err := regexp.Compile(`(?m)^\s*datadir\s*=\s*([^\s]+)`) if err != nil { - return "", "", "", err + return "", "", "", "", err } dataDirSubmatches := dataDirRE.FindSubmatch(configContents) if dataDirSubmatches != nil { @@ -1250,8 +1266,8 @@ func extractBitcoindRPCParams(bitcoindConfigPath string) (string, string, string if err == nil { splitCookie := strings.Split(string(cookie), ":") if len(splitCookie) == 2 { - return splitCookie[0], splitCookie[1], - string(zmqPathSubmatches[1]), nil + return splitCookie[0], splitCookie[1], zmqBlockHost, + zmqTxHost, nil } } @@ -1260,11 +1276,12 @@ func extractBitcoindRPCParams(bitcoindConfigPath string) (string, string, string // expression then we'll exit with an error. rpcUserRegexp, err := regexp.Compile(`(?m)^\s*rpcuser\s*=\s*([^\s]+)`) if err != nil { - return "", "", "", err + return "", "", "", "", err } userSubmatches := rpcUserRegexp.FindSubmatch(configContents) if userSubmatches == nil { - return "", "", "", fmt.Errorf("unable to find rpcuser in config") + return "", "", "", "", fmt.Errorf("unable to find rpcuser in " + + "config") } // Similarly, we'll use another regular expression to find the set @@ -1272,15 +1289,16 @@ func extractBitcoindRPCParams(bitcoindConfigPath string) (string, string, string // error. rpcPassRegexp, err := regexp.Compile(`(?m)^\s*rpcpassword\s*=\s*([^\s]+)`) if err != nil { - return "", "", "", err + return "", "", "", "", err } passSubmatches := rpcPassRegexp.FindSubmatch(configContents) if passSubmatches == nil { - return "", "", "", fmt.Errorf("unable to find rpcpassword in config") + return "", "", "", "", fmt.Errorf("unable to find rpcpassword " + + "in config") } return string(userSubmatches[1]), string(passSubmatches[1]), - string(zmqPathSubmatches[1]), nil + zmqBlockHost, zmqTxHost, nil } // normalizeNetwork returns the common name of a network type used to create