lnd: standardize printing to stdout

With this commit we standardize the error messages in the config parsing
section of the main package. We only print to stdout/stderr in a single
place and also make sure the same error is printed to the log (which
might or might not yet be initialized at that point).
This commit is contained in:
Oliver Gugger 2021-11-08 11:31:02 +01:00
parent 54584aabb6
commit 338afef862
No known key found for this signature in database
GPG Key ID: 8E4256593F177720
4 changed files with 257 additions and 237 deletions

View File

@ -53,7 +53,8 @@ type Config struct {
// queries if true. // queries if true.
HeightHintCacheQueryDisable bool HeightHintCacheQueryDisable bool
// NeutrinoMode defines settings for connecting to a neutrino light-client. // NeutrinoMode defines settings for connecting to a neutrino
// light-client.
NeutrinoMode *lncfg.Neutrino NeutrinoMode *lncfg.Neutrino
// BitcoindMode defines settings for connecting to a bitcoind node. // BitcoindMode defines settings for connecting to a bitcoind node.
@ -83,8 +84,8 @@ type Config struct {
// the main wallet. // the main wallet.
WalletUnlockParams *walletunlocker.WalletUnlockParams WalletUnlockParams *walletunlocker.WalletUnlockParams
// NeutrinoCS is a pointer to a neutrino ChainService. Must be non-nil if // NeutrinoCS is a pointer to a neutrino ChainService. Must be non-nil
// using neutrino. // if using neutrino.
NeutrinoCS *neutrino.ChainService NeutrinoCS *neutrino.ChainService
// ActiveNetParams details the current chain we are on. // ActiveNetParams details the current chain we are on.
@ -152,8 +153,8 @@ const (
BtcToLtcConversionRate = 60 BtcToLtcConversionRate = 60
) )
// DefaultLtcChannelConstraints is the default set of channel constraints that are // DefaultLtcChannelConstraints is the default set of channel constraints that
// meant to be used when initially funding a Litecoin channel. // are meant to be used when initially funding a Litecoin channel.
var DefaultLtcChannelConstraints = channeldb.ChannelConstraints{ var DefaultLtcChannelConstraints = channeldb.ChannelConstraints{
DustLimit: DefaultLitecoinDustLimit, DustLimit: DefaultLitecoinDustLimit,
MaxAcceptedHtlcs: input.MaxHTLCNumber / 2, MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
@ -285,8 +286,8 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) {
DefaultLitecoinStaticFeePerKW, 0, DefaultLitecoinStaticFeePerKW, 0,
) )
default: default:
return nil, nil, fmt.Errorf("default routing policy for chain %v is "+ return nil, nil, fmt.Errorf("default routing policy for chain "+
"unknown", cfg.PrimaryChain()) "%v is unknown", cfg.PrimaryChain())
} }
var err error var err error
@ -329,7 +330,8 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) {
if cfg.NeutrinoMode.FeeURL != "" { if cfg.NeutrinoMode.FeeURL != "" {
if cfg.FeeURL != "" { if cfg.FeeURL != "" {
return nil, nil, errors.New("feeurl and " + return nil, nil, errors.New("feeurl and " +
"neutrino.feeurl are mutually exclusive") "neutrino.feeurl are mutually " +
"exclusive")
} }
cfg.FeeURL = cfg.NeutrinoMode.FeeURL cfg.FeeURL = cfg.NeutrinoMode.FeeURL
@ -414,8 +416,8 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) {
} }
if err := bitcoindConn.Start(); err != nil { if err := bitcoindConn.Start(); err != nil {
return nil, nil, fmt.Errorf("unable to connect to bitcoind: "+ return nil, nil, fmt.Errorf("unable to connect to "+
"%v", err) "bitcoind: %v", err)
} }
cc.ChainNotifier = bitcoindnotify.New( cc.ChainNotifier = bitcoindnotify.New(
@ -439,8 +441,8 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) {
HTTPPostMode: true, HTTPPostMode: true,
} }
if cfg.Bitcoin.Active && !cfg.Bitcoin.RegTest { if cfg.Bitcoin.Active && !cfg.Bitcoin.RegTest {
log.Infof("Initializing bitcoind backed fee estimator in "+ log.Infof("Initializing bitcoind backed fee estimator "+
"%s mode", bitcoindMode.EstimateMode) "in %s mode", bitcoindMode.EstimateMode)
// Finally, we'll re-initialize the fee estimator, as // Finally, we'll re-initialize the fee estimator, as
// if we're using bitcoind as a backend, then we can // if we're using bitcoind as a backend, then we can
@ -455,8 +457,9 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) {
return nil, nil, err return nil, nil, err
} }
} else if cfg.Litecoin.Active && !cfg.Litecoin.RegTest { } else if cfg.Litecoin.Active && !cfg.Litecoin.RegTest {
log.Infof("Initializing litecoind backed fee estimator in "+ log.Infof("Initializing litecoind backed fee "+
"%s mode", bitcoindMode.EstimateMode) "estimator in %s mode",
bitcoindMode.EstimateMode)
// Finally, we'll re-initialize the fee estimator, as // Finally, we'll re-initialize the fee estimator, as
// if we're using litecoind as a backend, then we can // if we're using litecoind as a backend, then we can
@ -558,8 +561,8 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) {
return nil, nil, err return nil, nil, err
} }
// Finally, we'll create an instance of the default chain view to be // Finally, we'll create an instance of the default chain view
// used within the routing layer. // to be used within the routing layer.
cc.ChainView, err = chainview.NewBtcdFilteredChainView( cc.ChainView, err = chainview.NewBtcdFilteredChainView(
*rpcConfig, cfg.BlockCache, *rpcConfig, cfg.BlockCache,
) )
@ -568,10 +571,12 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) {
return nil, nil, err return nil, nil, err
} }
// Create a special websockets rpc client for btcd which will be used // Create a special websockets rpc client for btcd which will be
// by the wallet for notifications, calls, etc. // used by the wallet for notifications, calls, etc.
chainRPC, err := chain.NewRPCClient(cfg.ActiveNetParams.Params, btcdHost, chainRPC, err := chain.NewRPCClient(
btcdUser, btcdPass, rpcCert, false, 20) cfg.ActiveNetParams.Params, btcdHost, btcdUser,
btcdPass, rpcCert, false, 20,
)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -615,8 +620,8 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) {
case cfg.FeeURL == "" && cfg.Bitcoin.MainNet && case cfg.FeeURL == "" && cfg.Bitcoin.MainNet &&
homeChainConfig.Node == "neutrino": homeChainConfig.Node == "neutrino":
return nil, nil, fmt.Errorf("--feeurl parameter required when " + return nil, nil, fmt.Errorf("--feeurl parameter required " +
"running neutrino on mainnet") "when running neutrino on mainnet")
// Override default fee estimator if an external service is specified. // Override default fee estimator if an external service is specified.
case cfg.FeeURL != "": case cfg.FeeURL != "":
@ -638,7 +643,8 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) {
ccCleanup := func() { ccCleanup := func() {
if cc.FeeEstimator != nil { if cc.FeeEstimator != nil {
if err := cc.FeeEstimator.Stop(); err != nil { if err := cc.FeeEstimator.Stop(); err != nil {
log.Errorf("Failed to stop feeEstimator: %v", err) log.Errorf("Failed to stop feeEstimator: %v",
err)
} }
} }
} }
@ -686,12 +692,12 @@ func NewChainControl(walletConfig lnwallet.Config,
lnWallet, err := lnwallet.NewLightningWallet(walletConfig) lnWallet, err := lnwallet.NewLightningWallet(walletConfig)
if err != nil { if err != nil {
fmt.Printf("unable to create wallet: %v\n", err) return nil, ccCleanup, fmt.Errorf("unable to create wallet: %v",
return nil, ccCleanup, err err)
} }
if err := lnWallet.Startup(); err != nil { if err := lnWallet.Startup(); err != nil {
fmt.Printf("unable to start wallet: %v\n", err) return nil, ccCleanup, fmt.Errorf("unable to create wallet: %v",
return nil, ccCleanup, err err)
} }
log.Info("LightningWallet opened") log.Info("LightningWallet opened")
@ -872,7 +878,9 @@ func (c *ChainRegistry) LookupChain(targetChain ChainCode) (
// LookupChainByHash attempts to look up an active ChainControl which // LookupChainByHash attempts to look up an active ChainControl which
// corresponds to the passed genesis hash. // corresponds to the passed genesis hash.
func (c *ChainRegistry) LookupChainByHash(chainHash chainhash.Hash) (*ChainControl, bool) { func (c *ChainRegistry) LookupChainByHash(
chainHash chainhash.Hash) (*ChainControl, bool) {
c.RLock() c.RLock()
defer c.RUnlock() defer c.RUnlock()

407
config.go
View File

@ -647,15 +647,34 @@ func LoadConfig(interceptor signal.Interceptor) (*Config, error) {
} }
// Make sure everything we just loaded makes sense. // Make sure everything we just loaded makes sense.
cleanCfg, err := ValidateConfig(cfg, usageMessage, interceptor, cleanCfg, err := ValidateConfig(
fileParser, flagParser) cfg, interceptor, fileParser, flagParser,
)
if usageErr, ok := err.(*usageError); ok {
// The logging system might not yet be initialized, so we also
// write to stderr to make sure the error appears somewhere.
_, _ = fmt.Fprintln(os.Stderr, usageMessage)
ltndLog.Warnf("Incorrect usage: %v", usageMessage)
// The log subsystem might not yet be initialized. But we still
// try to log the error there since some packaging solutions
// might only look at the log and not stdout/stderr.
ltndLog.Warnf("Error validating config: %v", usageErr.err)
return nil, usageErr.err
}
if err != nil { if err != nil {
// The log subsystem might not yet be initialized. But we still
// try to log the error there since some packaging solutions
// might only look at the log and not stdout/stderr.
ltndLog.Warnf("Error validating config: %v", err)
return nil, err return nil, err
} }
// Warn about missing config file only after all other configuration is // Warn about missing config file only after all other configuration is
// done. This prevents the warning on help messages and invalid // done. This prevents the warning on help messages and invalid options.
// options. Note this should go directly before the return. // Note this should go directly before the return.
if configFileError != nil { if configFileError != nil {
ltndLog.Warnf("%v", configFileError) ltndLog.Warnf("%v", configFileError)
} }
@ -663,12 +682,24 @@ func LoadConfig(interceptor signal.Interceptor) (*Config, error) {
return cleanCfg, nil return cleanCfg, nil
} }
// usageError is an error type that signals a problem with the supplied flags.
type usageError struct {
err error
}
// Error returns the error string.
//
// NOTE: This is part of the error interface.
func (u *usageError) Error() string {
return u.err.Error()
}
// ValidateConfig check the given configuration to be sane. This makes sure no // ValidateConfig check the given configuration to be sane. This makes sure no
// illegal values or combination of values are set. All file system paths are // illegal values or combination of values are set. All file system paths are
// normalized. The cleaned up config is returned on success. // normalized. The cleaned up config is returned on success.
func ValidateConfig(cfg Config, usageMessage string, func ValidateConfig(cfg Config, interceptor signal.Interceptor, fileParser,
interceptor signal.Interceptor, fileParser,
flagParser *flags.Parser) (*Config, error) { flagParser *flags.Parser) (*Config, error) {
// If the provided lnd directory is not the default, we'll modify the // If the provided lnd directory is not the default, we'll modify the
// path to all of the files and directories that will live within it. // path to all of the files and directories that will live within it.
lndDir := CleanAndExpandPath(cfg.LndDir) lndDir := CleanAndExpandPath(cfg.LndDir)
@ -685,12 +716,16 @@ func ValidateConfig(cfg Config, usageMessage string,
// user has not requested a different location, we'll move the // user has not requested a different location, we'll move the
// location to be relative to the specified lnd directory. // location to be relative to the specified lnd directory.
if cfg.Watchtower.TowerDir == defaultTowerDir { if cfg.Watchtower.TowerDir == defaultTowerDir {
cfg.Watchtower.TowerDir = cfg.Watchtower.TowerDir = filepath.Join(
filepath.Join(cfg.DataDir, defaultTowerSubDirname) cfg.DataDir, defaultTowerSubDirname,
)
} }
} }
funcName := "loadConfig" funcName := "ValidateConfig"
mkErr := func(format string, args ...interface{}) error {
return fmt.Errorf(funcName+": "+format, args...)
}
makeDirectory := func(dir string) error { makeDirectory := func(dir string) error {
err := os.MkdirAll(dir, 0700) err := os.MkdirAll(dir, 0700)
if err != nil { if err != nil {
@ -705,10 +740,8 @@ func ValidateConfig(cfg Config, usageMessage string,
} }
} }
str := "%s: Failed to create lnd directory: %v" str := "Failed to create lnd directory: %v"
err := fmt.Errorf(str, funcName, err) return mkErr(str, err)
_, _ = fmt.Fprintln(os.Stderr, err)
return err
} }
return nil return nil
@ -716,21 +749,17 @@ func ValidateConfig(cfg Config, usageMessage string,
// IsSet returns true if an option has been set in either the config // IsSet returns true if an option has been set in either the config
// file or by a flag. // file or by a flag.
isSet := func(field string) bool { isSet := func(field string) (bool, error) {
fieldName, ok := reflect.TypeOf(Config{}).FieldByName(field) fieldName, ok := reflect.TypeOf(Config{}).FieldByName(field)
if !ok { if !ok {
str := "%s: could not find field %s" str := "could not find field %s"
err := fmt.Errorf(str, funcName, field) return false, mkErr(str, field)
_, _ = fmt.Fprintln(os.Stderr, err)
return false
} }
long, ok := fieldName.Tag.Lookup("long") long, ok := fieldName.Tag.Lookup("long")
if !ok { if !ok {
str := "%s: field %s does not have a long tag" str := "field %s does not have a long tag"
err := fmt.Errorf(str, funcName, field) return false, mkErr(str, field)
_, _ = fmt.Fprintln(os.Stderr, err)
return false
} }
// The user has the option to set the flag in either the config // The user has the option to set the flag in either the config
@ -751,9 +780,10 @@ func ValidateConfig(cfg Config, usageMessage string,
) )
return (fileOption != nil && fileOption.IsSet()) || return (fileOption != nil && fileOption.IsSet()) ||
(fileOptionNested != nil && fileOptionNested.IsSet()) || (fileOptionNested != nil && fileOptionNested.IsSet()) ||
(flagOption != nil && flagOption.IsSet()) || (flagOption != nil && flagOption.IsSet()) ||
(flagOptionNested != nil && flagOptionNested.IsSet()) (flagOptionNested != nil && flagOptionNested.IsSet()),
nil
} }
// As soon as we're done parsing configuration options, ensure all paths // As soon as we're done parsing configuration options, ensure all paths
@ -800,40 +830,28 @@ func ValidateConfig(cfg Config, usageMessage string,
// Ensure that the user didn't attempt to specify negative values for // Ensure that the user didn't attempt to specify negative values for
// any of the autopilot params. // any of the autopilot params.
if cfg.Autopilot.MaxChannels < 0 { if cfg.Autopilot.MaxChannels < 0 {
str := "%s: autopilot.maxchannels must be non-negative" str := "autopilot.maxchannels must be non-negative"
err := fmt.Errorf(str, funcName) return nil, mkErr(str)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
} }
if cfg.Autopilot.Allocation < 0 { if cfg.Autopilot.Allocation < 0 {
str := "%s: autopilot.allocation must be non-negative" str := "autopilot.allocation must be non-negative"
err := fmt.Errorf(str, funcName) return nil, mkErr(str)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
} }
if cfg.Autopilot.MinChannelSize < 0 { if cfg.Autopilot.MinChannelSize < 0 {
str := "%s: autopilot.minchansize must be non-negative" str := "autopilot.minchansize must be non-negative"
err := fmt.Errorf(str, funcName) return nil, mkErr(str)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
} }
if cfg.Autopilot.MaxChannelSize < 0 { if cfg.Autopilot.MaxChannelSize < 0 {
str := "%s: autopilot.maxchansize must be non-negative" str := "autopilot.maxchansize must be non-negative"
err := fmt.Errorf(str, funcName) return nil, mkErr(str)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
} }
if cfg.Autopilot.MinConfs < 0 { if cfg.Autopilot.MinConfs < 0 {
str := "%s: autopilot.minconfs must be non-negative" str := "autopilot.minconfs must be non-negative"
err := fmt.Errorf(str, funcName) return nil, mkErr(str)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
} }
if cfg.Autopilot.ConfTarget < 1 { if cfg.Autopilot.ConfTarget < 1 {
str := "%s: autopilot.conftarget must be positive" str := "autopilot.conftarget must be positive"
err := fmt.Errorf(str, funcName) return nil, mkErr(str)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
} }
// Ensure that the specified values for the min and max channel size // Ensure that the specified values for the min and max channel size
@ -846,7 +864,7 @@ func ValidateConfig(cfg Config, usageMessage string,
} }
if _, err := validateAtplCfg(cfg.Autopilot); err != nil { if _, err := validateAtplCfg(cfg.Autopilot); err != nil {
return nil, err return nil, mkErr("error validating autopilot: %v", err)
} }
// Ensure that --maxchansize is properly handled when set by user. // Ensure that --maxchansize is properly handled when set by user.
@ -865,32 +883,33 @@ func ValidateConfig(cfg Config, usageMessage string,
// Ensure that the user specified values for the min and max channel // Ensure that the user specified values for the min and max channel
// size make sense. // size make sense.
if cfg.MaxChanSize < cfg.MinChanSize { if cfg.MaxChanSize < cfg.MinChanSize {
return nil, fmt.Errorf("invalid channel size parameters: "+ return nil, mkErr("invalid channel size parameters: "+
"max channel size %v, must be no less than min chan size %v", "max channel size %v, must be no less than min chan "+
cfg.MaxChanSize, cfg.MinChanSize, "size %v", cfg.MaxChanSize, cfg.MinChanSize,
) )
} }
// Don't allow superflous --maxchansize greater than // Don't allow superflous --maxchansize greater than
// BOLT 02 soft-limit for non-wumbo channel // BOLT 02 soft-limit for non-wumbo channel
if !cfg.ProtocolOptions.Wumbo() && cfg.MaxChanSize > int64(MaxFundingAmount) { if !cfg.ProtocolOptions.Wumbo() &&
return nil, fmt.Errorf("invalid channel size parameters: "+ cfg.MaxChanSize > int64(MaxFundingAmount) {
"maximum channel size %v is greater than maximum non-wumbo"+
" channel size %v", return nil, mkErr("invalid channel size parameters: "+
cfg.MaxChanSize, MaxFundingAmount, "maximum channel size %v is greater than maximum "+
"non-wumbo channel size %v", cfg.MaxChanSize,
MaxFundingAmount,
) )
} }
// Ensure a valid max channel fee allocation was set. // Ensure a valid max channel fee allocation was set.
if cfg.MaxChannelFeeAllocation <= 0 || cfg.MaxChannelFeeAllocation > 1 { if cfg.MaxChannelFeeAllocation <= 0 || cfg.MaxChannelFeeAllocation > 1 {
return nil, fmt.Errorf("invalid max channel fee allocation: "+ return nil, mkErr("invalid max channel fee allocation: %v, "+
"%v, must be within (0, 1]", "must be within (0, 1]", cfg.MaxChannelFeeAllocation)
cfg.MaxChannelFeeAllocation)
} }
if cfg.MaxCommitFeeRateAnchors < 1 { if cfg.MaxCommitFeeRateAnchors < 1 {
return nil, fmt.Errorf("invalid max commit fee rate anchors: "+ return nil, mkErr("invalid max commit fee rate anchors: %v, "+
"%v, must be at least 1 sat/vbyte", "must be at least 1 sat/vByte",
cfg.MaxCommitFeeRateAnchors) cfg.MaxCommitFeeRateAnchors)
} }
@ -912,7 +931,7 @@ func ValidateConfig(cfg Config, usageMessage string,
cfg.net.ResolveTCPAddr, cfg.net.ResolveTCPAddr,
) )
if err != nil { if err != nil {
return nil, err return nil, mkErr("error parsing tor dns: %v", err)
} }
cfg.Tor.DNS = dns.String() cfg.Tor.DNS = dns.String()
} }
@ -922,25 +941,24 @@ func ValidateConfig(cfg Config, usageMessage string,
cfg.net.ResolveTCPAddr, cfg.net.ResolveTCPAddr,
) )
if err != nil { if err != nil {
return nil, err return nil, mkErr("error parsing tor control address: %v", err)
} }
cfg.Tor.Control = control.String() cfg.Tor.Control = control.String()
// Ensure that tor socks host:port is not equal to tor control // Ensure that tor socks host:port is not equal to tor control
// host:port. This would lead to lnd not starting up properly. // host:port. This would lead to lnd not starting up properly.
if cfg.Tor.SOCKS == cfg.Tor.Control { if cfg.Tor.SOCKS == cfg.Tor.Control {
str := "%s: tor.socks and tor.control can not use " + str := "tor.socks and tor.control can not us the same host:port"
"the same host:port" return nil, mkErr(str)
return nil, fmt.Errorf(str, funcName)
} }
switch { switch {
case cfg.Tor.V2 && cfg.Tor.V3: case cfg.Tor.V2 && cfg.Tor.V3:
return nil, errors.New("either tor.v2 or tor.v3 can be set, " + return nil, mkErr("either tor.v2 or tor.v3 can be set, " +
"but not both") "but not both")
case cfg.DisableListen && (cfg.Tor.V2 || cfg.Tor.V3): case cfg.DisableListen && (cfg.Tor.V2 || cfg.Tor.V3):
return nil, errors.New("listening must be enabled when " + return nil, mkErr("listening must be enabled when enabling " +
"enabling inbound connections over Tor") "inbound connections over Tor")
} }
if cfg.Tor.PrivateKeyPath == "" { if cfg.Tor.PrivateKeyPath == "" {
@ -960,11 +978,13 @@ func ValidateConfig(cfg Config, usageMessage string,
switch { switch {
case cfg.Tor.V2: case cfg.Tor.V2:
cfg.Tor.WatchtowerKeyPath = filepath.Join( cfg.Tor.WatchtowerKeyPath = filepath.Join(
cfg.Watchtower.TowerDir, defaultTorV2PrivateKeyFilename, cfg.Watchtower.TowerDir,
defaultTorV2PrivateKeyFilename,
) )
case cfg.Tor.V3: case cfg.Tor.V3:
cfg.Tor.WatchtowerKeyPath = filepath.Join( cfg.Tor.WatchtowerKeyPath = filepath.Join(
cfg.Watchtower.TowerDir, defaultTorV3PrivateKeyFilename, cfg.Watchtower.TowerDir,
defaultTorV3PrivateKeyFilename,
) )
} }
} }
@ -984,11 +1004,11 @@ func ValidateConfig(cfg Config, usageMessage string,
} }
if cfg.DisableListen && cfg.NAT { if cfg.DisableListen && cfg.NAT {
return nil, errors.New("NAT traversal cannot be used when " + return nil, mkErr("NAT traversal cannot be used when " +
"listening is disabled") "listening is disabled")
} }
if cfg.NAT && len(cfg.ExternalHosts) != 0 { if cfg.NAT && len(cfg.ExternalHosts) != 0 {
return nil, errors.New("NAT support and externalhosts are " + return nil, mkErr("NAT support and externalhosts are " +
"mutually exclusive, only one should be selected") "mutually exclusive, only one should be selected")
} }
@ -996,20 +1016,22 @@ func ValidateConfig(cfg Config, usageMessage string,
switch { switch {
// At this moment, multiple active chains are not supported. // At this moment, multiple active chains are not supported.
case cfg.Litecoin.Active && cfg.Bitcoin.Active: case cfg.Litecoin.Active && cfg.Bitcoin.Active:
str := "%s: Currently both Bitcoin and Litecoin cannot be " + str := "Currently both Bitcoin and Litecoin cannot be " +
"active together" "active together"
return nil, fmt.Errorf(str, funcName) return nil, mkErr(str)
// Either Bitcoin must be active, or Litecoin must be active. // Either Bitcoin must be active, or Litecoin must be active.
// Otherwise, we don't know which chain we're on. // Otherwise, we don't know which chain we're on.
case !cfg.Bitcoin.Active && !cfg.Litecoin.Active: case !cfg.Bitcoin.Active && !cfg.Litecoin.Active:
return nil, fmt.Errorf("%s: either bitcoin.active or "+ return nil, mkErr("either bitcoin.active or " +
"litecoin.active must be set to 1 (true)", funcName) "litecoin.active must be set to 1 (true)")
case cfg.Litecoin.Active: case cfg.Litecoin.Active:
err := cfg.Litecoin.Validate(minTimeLockDelta, funding.MinLtcRemoteDelay) err := cfg.Litecoin.Validate(
minTimeLockDelta, funding.MinLtcRemoteDelay,
)
if err != nil { if err != nil {
return nil, err return nil, mkErr("error validating litecoin: %v", err)
} }
// Multiple networks can't be selected simultaneously. Count // Multiple networks can't be selected simultaneously. Count
@ -1034,25 +1056,22 @@ func ValidateConfig(cfg Config, usageMessage string,
ltcParams = chainreg.LitecoinSimNetParams ltcParams = chainreg.LitecoinSimNetParams
} }
if cfg.Litecoin.SigNet { if cfg.Litecoin.SigNet {
return nil, fmt.Errorf("%s: litecoin.signet is not "+ return nil, mkErr("litecoin.signet is not supported")
"supported", funcName)
} }
if numNets > 1 { if numNets > 1 {
str := "%s: The mainnet, testnet, and simnet params " + str := "The mainnet, testnet, and simnet params " +
"can't be used together -- choose one of the " + "can't be used together -- choose one of the " +
"three" "three"
err := fmt.Errorf(str, funcName) return nil, mkErr(str)
return nil, err
} }
// The target network must be provided, otherwise, we won't // The target network must be provided, otherwise, we won't
// know how to initialize the daemon. // know how to initialize the daemon.
if numNets == 0 { if numNets == 0 {
str := "%s: either --litecoin.mainnet, or " + str := "either --litecoin.mainnet, or " +
"litecoin.testnet must be specified" "litecoin.testnet must be specified"
err := fmt.Errorf(str, funcName) return nil, mkErr(str)
return nil, err
} }
// The litecoin chain is the current active chain. However // The litecoin chain is the current active chain. However
@ -1063,36 +1082,39 @@ func ValidateConfig(cfg Config, usageMessage string,
switch cfg.Litecoin.Node { switch cfg.Litecoin.Node {
case "ltcd": case "ltcd":
err := parseRPCParams(cfg.Litecoin, cfg.LtcdMode, err := parseRPCParams(
chainreg.LitecoinChain, funcName, cfg.ActiveNetParams) cfg.Litecoin, cfg.LtcdMode,
chainreg.LitecoinChain, cfg.ActiveNetParams,
)
if err != nil { if err != nil {
err := fmt.Errorf("unable to load RPC "+ return nil, mkErr("unable to load RPC "+
"credentials for ltcd: %v", err) "credentials for ltcd: %v", err)
return nil, err
} }
case "litecoind": case "litecoind":
if cfg.Litecoin.SimNet { if cfg.Litecoin.SimNet {
return nil, fmt.Errorf("%s: litecoind does not "+ return nil, mkErr("litecoind does not " +
"support simnet", funcName) "support simnet")
} }
err := parseRPCParams(cfg.Litecoin, cfg.LitecoindMode, err := parseRPCParams(
chainreg.LitecoinChain, funcName, cfg.ActiveNetParams) cfg.Litecoin, cfg.LitecoindMode,
chainreg.LitecoinChain, cfg.ActiveNetParams,
)
if err != nil { if err != nil {
err := fmt.Errorf("unable to load RPC "+ return nil, mkErr("unable to load RPC "+
"credentials for litecoind: %v", err) "credentials for litecoind: %v", err)
return nil, err
} }
default: default:
str := "%s: only ltcd and litecoind mode supported for " + str := "only ltcd and litecoind mode supported for " +
"litecoin at this time" "litecoin at this time"
return nil, fmt.Errorf(str, funcName) return nil, mkErr(str)
} }
cfg.Litecoin.ChainDir = filepath.Join(cfg.DataDir, cfg.Litecoin.ChainDir = filepath.Join(
defaultChainSubDirname, cfg.DataDir, defaultChainSubDirname,
chainreg.LitecoinChain.String()) chainreg.LitecoinChain.String(),
)
// Finally we'll register the litecoin chain as our current // Finally, we'll register the litecoin chain as our current
// primary chain. // primary chain.
cfg.registeredChains.RegisterPrimaryChain(chainreg.LitecoinChain) cfg.registeredChains.RegisterPrimaryChain(chainreg.LitecoinChain)
MaxFundingAmount = funding.MaxLtcFundingAmount MaxFundingAmount = funding.MaxLtcFundingAmount
@ -1133,9 +1155,9 @@ func ValidateConfig(cfg Config, usageMessage string,
cfg.Bitcoin.SigNetChallenge, cfg.Bitcoin.SigNetChallenge,
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("%s: Invalid "+ return nil, mkErr("Invalid "+
"signet challenge, hex decode "+ "signet challenge, hex decode "+
"failed: %v", funcName, err) "failed: %v", err)
} }
sigNetChallenge = challenge sigNetChallenge = challenge
} }
@ -1158,66 +1180,66 @@ func ValidateConfig(cfg Config, usageMessage string,
cfg.ActiveNetParams.Params = &chainParams cfg.ActiveNetParams.Params = &chainParams
} }
if numNets > 1 { if numNets > 1 {
str := "%s: The mainnet, testnet, regtest, and " + str := "The mainnet, testnet, regtest, and simnet " +
"simnet params can't be used together -- " + "params can't be used together -- choose one " +
"choose one of the four" "of the four"
err := fmt.Errorf(str, funcName) return nil, mkErr(str)
return nil, err
} }
// The target network must be provided, otherwise, we won't // The target network must be provided, otherwise, we won't
// know how to initialize the daemon. // know how to initialize the daemon.
if numNets == 0 { if numNets == 0 {
str := "%s: either --bitcoin.mainnet, or " + str := "either --bitcoin.mainnet, or bitcoin.testnet," +
"bitcoin.testnet, bitcoin.simnet, or bitcoin.regtest " + "bitcoin.simnet, or bitcoin.regtest " +
"must be specified" "must be specified"
err := fmt.Errorf(str, funcName) return nil, mkErr(str)
return nil, err
} }
err := cfg.Bitcoin.Validate(minTimeLockDelta, funding.MinBtcRemoteDelay) err := cfg.Bitcoin.Validate(
minTimeLockDelta, funding.MinBtcRemoteDelay,
)
if err != nil { if err != nil {
return nil, err return nil, mkErr("error validating bitcoin params: %v",
err)
} }
switch cfg.Bitcoin.Node { switch cfg.Bitcoin.Node {
case "btcd": case "btcd":
err := parseRPCParams( err := parseRPCParams(
cfg.Bitcoin, cfg.BtcdMode, chainreg.BitcoinChain, funcName, cfg.Bitcoin, cfg.BtcdMode,
cfg.ActiveNetParams, chainreg.BitcoinChain, cfg.ActiveNetParams,
) )
if err != nil { if err != nil {
err := fmt.Errorf("unable to load RPC "+ return nil, mkErr("unable to load RPC "+
"credentials for btcd: %v", err) "credentials for btcd: %v", err)
return nil, err
} }
case "bitcoind": case "bitcoind":
if cfg.Bitcoin.SimNet { if cfg.Bitcoin.SimNet {
return nil, fmt.Errorf("%s: bitcoind does not "+ return nil, mkErr("bitcoind does not " +
"support simnet", funcName) "support simnet")
} }
err := parseRPCParams( err := parseRPCParams(
cfg.Bitcoin, cfg.BitcoindMode, chainreg.BitcoinChain, funcName, cfg.Bitcoin, cfg.BitcoindMode,
cfg.ActiveNetParams, chainreg.BitcoinChain, cfg.ActiveNetParams,
) )
if err != nil { if err != nil {
err := fmt.Errorf("unable to load RPC "+ return nil, mkErr("unable to load RPC "+
"credentials for bitcoind: %v", err) "credentials for bitcoind: %v", err)
return nil, err
} }
case "neutrino": case "neutrino":
// No need to get RPC parameters. // No need to get RPC parameters.
default: default:
str := "%s: only btcd, bitcoind, and neutrino mode " + str := "only btcd, bitcoind, and neutrino mode " +
"supported for bitcoin at this time" "supported for bitcoin at this time"
return nil, fmt.Errorf(str, funcName) return nil, mkErr(str)
} }
cfg.Bitcoin.ChainDir = filepath.Join(cfg.DataDir, cfg.Bitcoin.ChainDir = filepath.Join(
defaultChainSubDirname, cfg.DataDir, defaultChainSubDirname,
chainreg.BitcoinChain.String()) chainreg.BitcoinChain.String(),
)
// Finally we'll register the bitcoin chain as our current // Finally we'll register the bitcoin chain as our current
// primary chain. // primary chain.
@ -1227,28 +1249,20 @@ func ValidateConfig(cfg Config, usageMessage string,
// Ensure that the user didn't attempt to specify negative values for // Ensure that the user didn't attempt to specify negative values for
// any of the autopilot params. // any of the autopilot params.
if cfg.Autopilot.MaxChannels < 0 { if cfg.Autopilot.MaxChannels < 0 {
str := "%s: autopilot.maxchannels must be non-negative" str := "autopilot.maxchannels must be non-negative"
err := fmt.Errorf(str, funcName) return nil, mkErr(str)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
} }
if cfg.Autopilot.Allocation < 0 { if cfg.Autopilot.Allocation < 0 {
str := "%s: autopilot.allocation must be non-negative" str := "autopilot.allocation must be non-negative"
err := fmt.Errorf(str, funcName) return nil, mkErr(str)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
} }
if cfg.Autopilot.MinChannelSize < 0 { if cfg.Autopilot.MinChannelSize < 0 {
str := "%s: autopilot.minchansize must be non-negative" str := "autopilot.minchansize must be non-negative"
err := fmt.Errorf(str, funcName) return nil, mkErr(str)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
} }
if cfg.Autopilot.MaxChannelSize < 0 { if cfg.Autopilot.MaxChannelSize < 0 {
str := "%s: autopilot.maxchansize must be non-negative" str := "autopilot.maxchansize must be non-negative"
err := fmt.Errorf(str, funcName) return nil, mkErr(str)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
} }
// Ensure that the specified values for the min and max channel size // Ensure that the specified values for the min and max channel size
@ -1270,19 +1284,13 @@ func ValidateConfig(cfg Config, usageMessage string,
// Determine if the port is valid. // Determine if the port is valid.
profilePort, err := strconv.Atoi(hostPort) profilePort, err := strconv.Atoi(hostPort)
if err != nil || profilePort < 1024 || profilePort > 65535 { if err != nil || profilePort < 1024 || profilePort > 65535 {
err = fmt.Errorf(str, funcName) return nil, &usageError{mkErr(str)}
_, _ = fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, usageMessage)
return nil, err
} }
} else { } else {
// Try to parse Profile as a port. // Try to parse Profile as a port.
profilePort, err := strconv.Atoi(cfg.Profile) profilePort, err := strconv.Atoi(cfg.Profile)
if err != nil || profilePort < 1024 || profilePort > 65535 { if err != nil || profilePort < 1024 || profilePort > 65535 {
err = fmt.Errorf(str, funcName) return nil, &usageError{mkErr(str)}
_, _ = fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, usageMessage)
return nil, err
} }
// Since the user just set a port, we will serve debugging // Since the user just set a port, we will serve debugging
@ -1334,14 +1342,15 @@ func ValidateConfig(cfg Config, usageMessage string,
// Append the network type to the log directory so it is "namespaced" // Append the network type to the log directory so it is "namespaced"
// per network in the same fashion as the data directory. // per network in the same fashion as the data directory.
cfg.LogDir = filepath.Join(cfg.LogDir, cfg.LogDir = filepath.Join(
cfg.registeredChains.PrimaryChain().String(), cfg.LogDir, cfg.registeredChains.PrimaryChain().String(),
lncfg.NormalizeNetwork(cfg.ActiveNetParams.Name)) lncfg.NormalizeNetwork(cfg.ActiveNetParams.Name),
)
// A log writer must be passed in, otherwise we can't function and would // A log writer must be passed in, otherwise we can't function and would
// run into a panic later on. // run into a panic later on.
if cfg.LogWriter == nil { if cfg.LogWriter == nil {
return nil, fmt.Errorf("log writer missing in config") return nil, mkErr("log writer missing in config")
} }
// Special show command to list supported subsystems and exit. // Special show command to list supported subsystems and exit.
@ -1358,19 +1367,15 @@ func ValidateConfig(cfg Config, usageMessage string,
cfg.MaxLogFileSize, cfg.MaxLogFiles, cfg.MaxLogFileSize, cfg.MaxLogFiles,
) )
if err != nil { if err != nil {
str := "%s: log rotation setup failed: %v" str := "log rotation setup failed: %v"
err = fmt.Errorf(str, funcName, err.Error()) return nil, mkErr(str, err)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
} }
// Parse, validate, and set debug log level(s). // Parse, validate, and set debug log level(s).
err = build.ParseAndSetDebugLevels(cfg.DebugLevel, cfg.LogWriter) err = build.ParseAndSetDebugLevels(cfg.DebugLevel, cfg.LogWriter)
if err != nil { if err != nil {
err = fmt.Errorf("%s: %v", funcName, err.Error()) str := "error parsing debug level: %v"
_, _ = fmt.Fprintln(os.Stderr, err) return nil, &usageError{mkErr(str, err)}
_, _ = fmt.Fprintln(os.Stderr, usageMessage)
return nil, err
} }
// At least one RPCListener is required. So listen on localhost per // At least one RPCListener is required. So listen on localhost per
@ -1406,7 +1411,7 @@ func ValidateConfig(cfg Config, usageMessage string,
cfg.net.ResolveTCPAddr, cfg.net.ResolveTCPAddr,
) )
if err != nil { if err != nil {
return nil, err return nil, mkErr("error normalizing RPC listen addrs: %v", err)
} }
// Add default port to all REST listener addresses if needed and remove // Add default port to all REST listener addresses if needed and remove
@ -1416,25 +1421,25 @@ func ValidateConfig(cfg Config, usageMessage string,
cfg.net.ResolveTCPAddr, cfg.net.ResolveTCPAddr,
) )
if err != nil { if err != nil {
return nil, err return nil, mkErr("error normalizing REST listen addrs: %v", err)
} }
switch { switch {
// The no seed backup and auto unlock are mutually exclusive. // The no seed backup and auto unlock are mutually exclusive.
case cfg.NoSeedBackup && cfg.WalletUnlockPasswordFile != "": case cfg.NoSeedBackup && cfg.WalletUnlockPasswordFile != "":
return nil, fmt.Errorf("cannot set noseedbackup and " + return nil, mkErr("cannot set noseedbackup and " +
"wallet-unlock-password-file at the same time") "wallet-unlock-password-file at the same time")
// The "allow-create" flag cannot be set without the auto unlock file. // The "allow-create" flag cannot be set without the auto unlock file.
case cfg.WalletUnlockAllowCreate && cfg.WalletUnlockPasswordFile == "": case cfg.WalletUnlockAllowCreate && cfg.WalletUnlockPasswordFile == "":
return nil, fmt.Errorf("cannot set wallet-unlock-allow-create " + return nil, mkErr("cannot set wallet-unlock-allow-create " +
"without wallet-unlock-password-file") "without wallet-unlock-password-file")
// If a password file was specified, we need it to exist. // If a password file was specified, we need it to exist.
case cfg.WalletUnlockPasswordFile != "" && case cfg.WalletUnlockPasswordFile != "" &&
!lnrpc.FileExists(cfg.WalletUnlockPasswordFile): !lnrpc.FileExists(cfg.WalletUnlockPasswordFile):
return nil, fmt.Errorf("wallet unlock password file %s does "+ return nil, mkErr("wallet unlock password file %s does "+
"not exist", cfg.WalletUnlockPasswordFile) "not exist", cfg.WalletUnlockPasswordFile)
} }
@ -1446,7 +1451,8 @@ func ValidateConfig(cfg Config, usageMessage string,
cfg.RPCListeners, !cfg.NoMacaroons, true, cfg.RPCListeners, !cfg.NoMacaroons, true,
) )
if err != nil { if err != nil {
return nil, err return nil, mkErr("error enforcing safe authentication on "+
"RPC ports: %v", err)
} }
if cfg.DisableRest { if cfg.DisableRest {
@ -1457,7 +1463,8 @@ func ValidateConfig(cfg Config, usageMessage string,
cfg.RESTListeners, !cfg.NoMacaroons, !cfg.DisableRestTLS, cfg.RESTListeners, !cfg.NoMacaroons, !cfg.DisableRestTLS,
) )
if err != nil { if err != nil {
return nil, err return nil, mkErr("error enforcing safe "+
"authentication on REST ports: %v", err)
} }
} }
@ -1475,7 +1482,8 @@ func ValidateConfig(cfg Config, usageMessage string,
cfg.net.ResolveTCPAddr, cfg.net.ResolveTCPAddr,
) )
if err != nil { if err != nil {
return nil, err return nil, mkErr("error normalizing p2p listen "+
"addrs: %v", err)
} }
// Add default port to all external IP addresses if needed and remove // Add default port to all external IP addresses if needed and remove
@ -1493,10 +1501,9 @@ func ValidateConfig(cfg Config, usageMessage string,
// that. // that.
for _, p2pListener := range cfg.Listeners { for _, p2pListener := range cfg.Listeners {
if lncfg.IsUnix(p2pListener) { if lncfg.IsUnix(p2pListener) {
err := fmt.Errorf("unix socket addresses cannot be "+ return nil, mkErr("unix socket addresses "+
"used for the p2p connection listener: %s", "cannot be used for the p2p "+
p2pListener) "connection listener: %s", p2pListener)
return nil, err
} }
} }
} }
@ -1504,15 +1511,18 @@ func ValidateConfig(cfg Config, usageMessage string,
// Ensure that the specified minimum backoff is below or equal to the // Ensure that the specified minimum backoff is below or equal to the
// maximum backoff. // maximum backoff.
if cfg.MinBackoff > cfg.MaxBackoff { if cfg.MinBackoff > cfg.MaxBackoff {
return nil, fmt.Errorf("maxbackoff must be greater than " + return nil, mkErr("maxbackoff must be greater than minbackoff")
"minbackoff")
} }
// Newer versions of lnd added a new sub-config for bolt-specific // Newer versions of lnd added a new sub-config for bolt-specific
// parameters. However we want to also allow existing users to use the // parameters. However, we want to also allow existing users to use the
// value on the top-level config. If the outer config value is set, // value on the top-level config. If the outer config value is set,
// then we'll use that directly. // then we'll use that directly.
if isSet("SyncFreelist") { flagSet, err := isSet("SyncFreelist")
if err != nil {
return nil, mkErr("error parsing freelist sync flag: %v", err)
}
if flagSet {
cfg.DB.Bolt.NoFreelistSync = !cfg.SyncFreelist cfg.DB.Bolt.NoFreelistSync = !cfg.SyncFreelist
} }
@ -1520,13 +1530,13 @@ func ValidateConfig(cfg Config, usageMessage string,
// than the protocol maximum. // than the protocol maximum.
maxRemoteHtlcs := uint16(input.MaxHTLCNumber / 2) maxRemoteHtlcs := uint16(input.MaxHTLCNumber / 2)
if cfg.DefaultRemoteMaxHtlcs > maxRemoteHtlcs { if cfg.DefaultRemoteMaxHtlcs > maxRemoteHtlcs {
return nil, fmt.Errorf("default-remote-max-htlcs (%v) must be "+ return nil, mkErr("default-remote-max-htlcs (%v) must be "+
"less than %v", cfg.DefaultRemoteMaxHtlcs, "less than %v", cfg.DefaultRemoteMaxHtlcs,
maxRemoteHtlcs) maxRemoteHtlcs)
} }
if err := cfg.Gossip.Parse(); err != nil { if err := cfg.Gossip.Parse(); err != nil {
return nil, err return nil, mkErr("error parsing gossip syncer: %v", err)
} }
// Log a warning if our expiry delta is not greater than our incoming // Log a warning if our expiry delta is not greater than our incoming
@ -1560,11 +1570,11 @@ func ValidateConfig(cfg Config, usageMessage string,
// the wallet. // the wallet.
_, err = parseHexColor(cfg.Color) _, err = parseHexColor(cfg.Color)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to parse node color: %v", err) return nil, mkErr("unable to parse node color: %v", err)
} }
// All good, return the sanitized result. // All good, return the sanitized result.
return &cfg, err return &cfg, nil
} }
// graphDatabaseDir returns the default directory where the local bolt graph db // graphDatabaseDir returns the default directory where the local bolt graph db
@ -1636,8 +1646,7 @@ func CleanAndExpandPath(path string) string {
} }
func parseRPCParams(cConfig *lncfg.Chain, nodeConfig interface{}, func parseRPCParams(cConfig *lncfg.Chain, nodeConfig interface{},
net chainreg.ChainCode, funcName string, net chainreg.ChainCode, netParams chainreg.BitcoinNetParams) error {
netParams chainreg.BitcoinNetParams) error { // nolint:unparam
// First, we'll check our node config to make sure the RPC parameters // First, we'll check our node config to make sure the RPC parameters
// were set correctly. We'll also determine the path to the conf file // were set correctly. We'll also determine the path to the conf file
@ -1726,9 +1735,8 @@ func parseRPCParams(cConfig *lncfg.Chain, nodeConfig interface{},
// the RPC credentials from the configuration. So if lnd wasn't // the RPC credentials from the configuration. So if lnd wasn't
// specified the parameters, then we won't be able to start. // specified the parameters, then we won't be able to start.
if cConfig.SimNet { if cConfig.SimNet {
str := "%v: rpcuser and rpcpass must be set to your btcd " + return fmt.Errorf("rpcuser and rpcpass must be set to your " +
"node's RPC parameters for simnet mode" "btcd node's RPC parameters for simnet mode")
return fmt.Errorf(str, funcName)
} }
fmt.Println("Attempting automatic RPC configuration to " + daemonName) fmt.Println("Attempting automatic RPC configuration to " + daemonName)
@ -1739,19 +1747,18 @@ func parseRPCParams(cConfig *lncfg.Chain, nodeConfig interface{},
nConf := nodeConfig.(*lncfg.Btcd) nConf := nodeConfig.(*lncfg.Btcd)
rpcUser, rpcPass, err := extractBtcdRPCParams(confFile) rpcUser, rpcPass, err := extractBtcdRPCParams(confFile)
if err != nil { if err != nil {
return fmt.Errorf("unable to extract RPC credentials:"+ return fmt.Errorf("unable to extract RPC credentials: "+
" %v, cannot start w/o RPC connection", "%v, cannot start w/o RPC connection", err)
err)
} }
nConf.RPCUser, nConf.RPCPass = rpcUser, rpcPass nConf.RPCUser, nConf.RPCPass = rpcUser, rpcPass
case "bitcoind", "litecoind": case "bitcoind", "litecoind":
nConf := nodeConfig.(*lncfg.Bitcoind) nConf := nodeConfig.(*lncfg.Bitcoind)
rpcUser, rpcPass, zmqBlockHost, zmqTxHost, err := rpcUser, rpcPass, zmqBlockHost, zmqTxHost, err :=
extractBitcoindRPCParams(netParams.Params.Name, confFile) extractBitcoindRPCParams(netParams.Params.Name, confFile)
if err != nil { if err != nil {
return fmt.Errorf("unable to extract RPC credentials:"+ return fmt.Errorf("unable to extract RPC credentials: "+
" %v, cannot start w/o RPC connection", "%v, cannot start w/o RPC connection", err)
err)
} }
nConf.RPCUser, nConf.RPCPass = rpcUser, rpcPass nConf.RPCUser, nConf.RPCPass = rpcUser, rpcPass
nConf.ZMQPubRawBlock, nConf.ZMQPubRawTx = zmqBlockHost, zmqTxHost nConf.ZMQPubRawBlock, nConf.ZMQPubRawTx = zmqBlockHost, zmqTxHost

View File

@ -601,7 +601,7 @@ func (d *DefaultWalletImpl) BuildChainControl(
*walletConfig, partialChainControl.Cfg.BlockCache, *walletConfig, partialChainControl.Cfg.BlockCache,
) )
if err != nil { if err != nil {
fmt.Printf("unable to create wallet controller: %v\n", err) err := fmt.Errorf("unable to create wallet controller: %v", err)
d.logger.Error(err) d.logger.Error(err)
return nil, nil, err return nil, nil, err
} }
@ -676,7 +676,7 @@ func (d *RPCSignerWalletImpl) BuildChainControl(
*walletConfig, partialChainControl.Cfg.BlockCache, *walletConfig, partialChainControl.Cfg.BlockCache,
) )
if err != nil { if err != nil {
fmt.Printf("unable to create wallet controller: %v\n", err) err := fmt.Errorf("unable to create wallet controller: %v", err)
d.logger.Error(err) d.logger.Error(err)
return nil, nil, err return nil, nil, err
} }
@ -691,7 +691,8 @@ func (d *RPCSignerWalletImpl) BuildChainControl(
rpcwallet.DefaultRPCTimeout, rpcwallet.DefaultRPCTimeout,
) )
if err != nil { if err != nil {
fmt.Printf("unable to create RPC remote signing wallet %v", err) err := fmt.Errorf("unable to create RPC remote signing wallet "+
"%v", err)
d.logger.Error(err) d.logger.Error(err)
return nil, nil, err return nil, nil, err
} }

16
lnd.go
View File

@ -403,12 +403,14 @@ func Main(cfg *Config, lisCfg ListenerCfg, implCfg *ImplementationCfg,
if cfg.Tor.Active { if cfg.Tor.Active {
if cfg.Tor.SkipProxyForClearNetTargets { if cfg.Tor.SkipProxyForClearNetTargets {
srvrLog.Info("Onion services are accessible via Tor! NOTE: " + srvrLog.Info("Onion services are accessible via Tor! " +
"Traffic to clearnet services is not routed via Tor.") "NOTE: Traffic to clearnet services is not " +
"routed via Tor.")
} else { } else {
srvrLog.Infof("Proxying all network traffic via Tor "+ srvrLog.Infof("Proxying all network traffic via Tor "+
"(stream_isolation=%v)! NOTE: Ensure the backend node "+ "(stream_isolation=%v)! NOTE: Ensure the "+
"is proxying over Tor as well", cfg.Tor.StreamIsolation) "backend node is proxying over Tor as well",
cfg.Tor.StreamIsolation)
} }
} }
@ -423,13 +425,15 @@ func Main(cfg *Config, lisCfg ListenerCfg, implCfg *ImplementationCfg,
// Start the tor controller before giving it to any other subsystems. // Start the tor controller before giving it to any other subsystems.
if err := torController.Start(); err != nil { if err := torController.Start(); err != nil {
err := fmt.Errorf("unable to initialize tor controller: %v", err) err := fmt.Errorf("unable to initialize tor "+
"controller: %v", err)
ltndLog.Error(err) ltndLog.Error(err)
return err return err
} }
defer func() { defer func() {
if err := torController.Stop(); err != nil { if err := torController.Stop(); err != nil {
ltndLog.Errorf("error stopping tor controller: %v", err) ltndLog.Errorf("error stopping tor "+
"controller: %v", err)
} }
}() }()
} }