github.com/decred/dcrlnd@v0.7.6/config.go (about) 1 // Copyright (c) 2013-2017 The btcsuite developers 2 // Copyright (c) 2015-2019 The Decred developers 3 // Copyright (C) 2015-2020 The Lightning Network Developers 4 5 package dcrlnd 6 7 import ( 8 "fmt" 9 "io/ioutil" 10 "net" 11 "os" 12 "os/user" 13 "path/filepath" 14 "reflect" 15 "regexp" 16 "runtime" 17 "strconv" 18 "strings" 19 "time" 20 21 "github.com/decred/dcrd/dcrutil/v4" 22 "github.com/decred/dcrd/wire" 23 "github.com/decred/dcrlnd/autopilot" 24 "github.com/decred/dcrlnd/build" 25 "github.com/decred/dcrlnd/chainreg" 26 "github.com/decred/dcrlnd/chanbackup" 27 "github.com/decred/dcrlnd/channeldb" 28 "github.com/decred/dcrlnd/discovery" 29 "github.com/decred/dcrlnd/funding" 30 "github.com/decred/dcrlnd/htlcswitch" 31 "github.com/decred/dcrlnd/htlcswitch/hodl" 32 "github.com/decred/dcrlnd/input" 33 "github.com/decred/dcrlnd/lncfg" 34 "github.com/decred/dcrlnd/lnrpc" 35 "github.com/decred/dcrlnd/lnrpc/routerrpc" 36 "github.com/decred/dcrlnd/lnrpc/signrpc" 37 "github.com/decred/dcrlnd/lnwallet" 38 "github.com/decred/dcrlnd/routing" 39 "github.com/decred/dcrlnd/signal" 40 "github.com/decred/dcrlnd/tor" 41 flags "github.com/jessevdk/go-flags" 42 ) 43 44 const ( 45 defaultDataDirname = "data" 46 defaultChainSubDirname = "chain" 47 defaultGraphSubDirname = "graph" 48 defaultTowerSubDirname = "watchtower" 49 defaultTLSCertFilename = "tls.cert" 50 defaultTLSKeyFilename = "tls.key" 51 defaultAdminMacFilename = "admin.macaroon" 52 defaultReadMacFilename = "readonly.macaroon" 53 defaultInvoiceMacFilename = "invoice.macaroon" 54 defaultLogLevel = "info" 55 defaultLogDirname = "logs" 56 defaultLogFilename = "lnd.log" 57 defaultRPCPort = 10009 58 defaultRESTPort = 8080 59 defaultPeerPort = 9735 60 defaultRPCHost = "localhost" 61 62 defaultNoSeedBackup = false 63 defaultPaymentsExpirationGracePeriod = time.Duration(0) 64 defaultTrickleDelay = 90 * 1000 65 defaultChanStatusSampleInterval = time.Minute 66 defaultChanEnableTimeout = 19 * time.Minute 67 defaultChanDisableTimeout = 20 * time.Minute 68 defaultHeightHintCacheQueryDisable = false 69 defaultMaxLogFiles = 3 70 defaultMaxLogFileSize = 10 71 defaultMinBackoff = time.Second 72 defaultMaxBackoff = time.Hour 73 defaultLetsEncryptDirname = "letsencrypt" 74 defaultLetsEncryptListen = ":80" 75 76 defaultTorSOCKSPort = 9050 77 defaultTorDNSHost = "soa.nodes.lightning.directory" 78 defaultTorDNSPort = 53 79 defaultTorControlPort = 9051 80 defaultTorV2PrivateKeyFilename = "v2_onion_private_key" 81 defaultTorV3PrivateKeyFilename = "v3_onion_private_key" 82 83 // DefaultAutogenValidity is the default validity of a self-signed 84 // certificate. The value corresponds to 14 months 85 // (14 months * 30 days * 24 hours). 86 defaultTLSCertDuration = 14 * 30 * 24 * time.Hour 87 88 // minTimeLockDelta is the minimum timelock we require for incoming 89 // HTLCs on our channels. 90 minTimeLockDelta = routing.MinCLTVDelta 91 92 // defaultAcceptorTimeout is the time after which an RPCAcceptor will time 93 // out and return false if it hasn't yet received a response. 94 defaultAcceptorTimeout = 15 * time.Second 95 96 defaultAlias = "" 97 defaultColor = "#3399FF" 98 99 // defaultCoopCloseTargetConfs is the default confirmation target 100 // that will be used to estimate a fee rate to use during a 101 // cooperative channel closure initiated by a remote peer. By default 102 // we'll set this to a lax value since we weren't the ones that 103 // initiated the channel closure. 104 defaultCoopCloseTargetConfs = 6 105 106 // defaultBlockCacheSize is the size (in bytes) of blocks that will be 107 // keep in memory if no size is specified. 108 defaultBlockCacheSize uint64 = 20 * 1024 * 1024 // 20 MB 109 110 // defaultHostSampleInterval is the default amount of time that the 111 // HostAnnouncer will wait between DNS resolutions to check if the 112 // backing IP of a host has changed. 113 defaultHostSampleInterval = time.Minute * 5 114 115 defaultChainInterval = time.Minute 116 defaultChainTimeout = time.Second * 30 117 defaultChainBackoff = time.Minute * 2 118 defaultChainAttempts = 3 119 120 // Set defaults for a health check which ensures that we have space 121 // available on disk. Although this check is off by default so that we 122 // avoid breaking any existing setups (particularly on mobile), we still 123 // set the other default values so that the health check can be easily 124 // enabled with sane defaults. 125 defaultRequiredDisk = 0.1 126 defaultDiskInterval = time.Hour * 12 127 defaultDiskTimeout = time.Second * 5 128 defaultDiskBackoff = time.Minute 129 defaultDiskAttempts = 0 130 131 // Set defaults for a health check which ensures that the TLS certificate 132 // is not expired. Although this check is off by default (not all setups 133 // require it), we still set the other default values so that the health 134 // check can be easily enabled with sane defaults. 135 defaultTLSInterval = time.Minute 136 defaultTLSTimeout = time.Second * 5 137 defaultTLSBackoff = time.Minute 138 defaultTLSAttempts = 0 139 140 // Set defaults for a health check which ensures that the tor 141 // connection is alive. Although this check is off by default (not all 142 // setups require it), we still set the other default values so that 143 // the health check can be easily enabled with sane defaults. 144 defaultTCInterval = time.Minute 145 defaultTCTimeout = time.Second * 5 146 defaultTCBackoff = time.Minute 147 defaultTCAttempts = 0 148 149 // defaultRemoteMaxHtlcs specifies the default limit for maximum 150 // concurrent HTLCs the remote party may add to commitment transactions. 151 // This value can be overridden with --default-remote-max-htlcs. 152 defaultRemoteMaxHtlcs = input.MaxHTLCNumber / 2 153 154 // defaultMaxLocalCSVDelay is the maximum delay we accept on our 155 // commitment output. 156 // TODO(halseth): find a more scientific choice of value. 157 defaultMaxLocalCSVDelay = 10000 158 159 // defaultChannelCommitInterval is the default maximum time between receiving a 160 // channel state update and signing a new commitment. 161 defaultChannelCommitInterval = 50 * time.Millisecond 162 163 // defaultChannelCommitBatchSize is the default maximum number of 164 // channel state updates that is accumulated before signing a new 165 // commitment. 166 defaultChannelCommitBatchSize = 10 167 168 // defaultCoinSelectionStrategy is the coin selection strategy that is 169 // used by default to fund transactions. 170 defaultCoinSelectionStrategy = "random" 171 ) 172 173 var ( 174 // DefaultLndDir is the default directory where lnd tries to find its 175 // configuration file and store its data. This is a directory in the 176 // user's application data, for example: 177 // C:\Users\<username>\AppData\Local\Lnd on Windows ~/.lnd on Linux 178 // ~/Library/Application Support/Lnd on MacOS 179 DefaultLndDir = dcrutil.AppDataDir("dcrlnd", false) 180 181 // DefaultConfigFile is the default full path of lnd's configuration 182 // file. 183 DefaultConfigFile = filepath.Join(DefaultLndDir, lncfg.DefaultConfigFilename) 184 185 defaultDataDir = filepath.Join(DefaultLndDir, defaultDataDirname) 186 defaultLogDir = filepath.Join(DefaultLndDir, defaultLogDirname) 187 188 defaultTowerDir = filepath.Join(defaultDataDir, defaultTowerSubDirname) 189 190 defaultTLSCertPath = filepath.Join(DefaultLndDir, defaultTLSCertFilename) 191 defaultTLSKeyPath = filepath.Join(DefaultLndDir, defaultTLSKeyFilename) 192 defaultLetsEncryptDir = filepath.Join(DefaultLndDir, defaultLetsEncryptDirname) 193 194 defaultDcrdDir = dcrutil.AppDataDir("dcrd", false) 195 defaultDcrdRPCCertFile = filepath.Join(defaultDcrdDir, "rpc.cert") 196 197 defaultTorSOCKS = net.JoinHostPort("localhost", strconv.Itoa(defaultTorSOCKSPort)) 198 defaultTorDNS = net.JoinHostPort(defaultTorDNSHost, strconv.Itoa(defaultTorDNSPort)) 199 defaultTorControl = net.JoinHostPort("localhost", strconv.Itoa(defaultTorControlPort)) 200 ) 201 202 // Config defines the configuration options for lnd. 203 // 204 // See LoadConfig for further details regarding the configuration 205 // loading+parsing process. 206 type Config struct { 207 ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"` 208 209 LndDir string `long:"lnddir" description:"The base directory that contains lnd's data, logs, configuration file, etc."` 210 ConfigFile string `short:"C" long:"configfile" description:"Path to configuration file"` 211 DataDir string `short:"b" long:"datadir" description:"The directory to store lnd's data within"` 212 SyncFreelist bool `long:"sync-freelist" description:"Whether the databases used within lnd should sync their freelist to disk. This is disabled by default resulting in improved memory performance during operation, but with an increase in startup time."` 213 214 TLSCertPath string `long:"tlscertpath" description:"Path to write the TLS certificate for lnd's RPC and REST services"` 215 TLSKeyPath string `long:"tlskeypath" description:"Path to write the TLS private key for lnd's RPC and REST services"` 216 TLSExtraIPs []string `long:"tlsextraip" description:"Adds an extra ip to the generated certificate"` 217 TLSExtraDomains []string `long:"tlsextradomain" description:"Adds an extra domain to the generated certificate"` 218 TLSAutoRefresh bool `long:"tlsautorefresh" description:"Re-generate TLS certificate and key if the IPs or domains are changed"` 219 TLSDisableAutofill bool `long:"tlsdisableautofill" description:"Do not include the interface IPs or the system hostname in TLS certificate, use first --tlsextradomain as Common Name instead, if set"` 220 TLSCertDuration time.Duration `long:"tlscertduration" description:"The duration for which the auto-generated TLS certificate will be valid for"` 221 222 NoMacaroons bool `long:"no-macaroons" description:"Disable macaroon authentication"` 223 AdminMacPath string `long:"adminmacaroonpath" description:"Path to write the admin macaroon for lnd's RPC and REST services if it doesn't exist"` 224 ReadMacPath string `long:"readonlymacaroonpath" description:"Path to write the read-only macaroon for lnd's RPC and REST services if it doesn't exist"` 225 InvoiceMacPath string `long:"invoicemacaroonpath" description:"Path to the invoice-only macaroon for lnd's RPC and REST services if it doesn't exist"` 226 LogDir string `long:"logdir" description:"Directory to log output."` 227 MaxLogFiles int `long:"maxlogfiles" description:"Maximum logfiles to keep (0 for no rotation)"` 228 MaxLogFileSize int `long:"maxlogfilesize" description:"Maximum logfile size in MB"` 229 AcceptorTimeout time.Duration `long:"acceptortimeout" description:"Time after which an RPCAcceptor will time out and return false if it hasn't yet received a response"` 230 231 // IPC options 232 PipeTx *uint `long:"pipetx" description:"File descriptor or handle of write end pipe to enable child -> parent process communication"` 233 PipeRx *uint `long:"piperx" description:"File descriptor or handle of read end pipe to enable parent -> child process communication"` 234 RPCListenerEvents bool `long:"rpclistenerevents" description:"Notify JSON-RPC and gRPC listener addresses over the TX pipe"` 235 236 LetsEncryptDir string `long:"letsencryptdir" description:"The directory to store Let's Encrypt certificates within"` 237 LetsEncryptListen string `long:"letsencryptlisten" description:"The IP:port on which lnd will listen for Let's Encrypt challenges. Let's Encrypt will always try to contact on port 80. Often non-root processes are not allowed to bind to ports lower than 1024. This configuration option allows a different port to be used, but must be used in combination with port forwarding from port 80. This configuration can also be used to specify another IP address to listen on, for example an IPv6 address."` 238 LetsEncryptDomain string `long:"letsencryptdomain" description:"Request a Let's Encrypt certificate for this domain. Note that the certicate is only requested and stored when the first rpc connection comes in."` 239 240 // We'll parse these 'raw' string arguments into real net.Addrs in the 241 // loadConfig function. We need to expose the 'raw' strings so the 242 // command line library can access them. 243 // Only the parsed net.Addrs should be used! 244 RawRPCListeners []string `long:"rpclisten" description:"Add an interface/port/socket to listen for RPC connections"` 245 RawRESTListeners []string `long:"restlisten" description:"Add an interface/port/socket to listen for REST connections"` 246 RawListeners []string `long:"listen" description:"Add an interface/port to listen for peer connections"` 247 RawExternalIPs []string `long:"externalip" description:"Add an ip:port to the list of local addresses we claim to listen on to peers. If a port is not specified, the default (9735) will be used regardless of other parameters"` 248 ExternalHosts []string `long:"externalhosts" description:"A set of hosts that should be periodically resolved to announce IPs for"` 249 RPCListeners []net.Addr 250 RESTListeners []net.Addr 251 RestCORS []string `long:"restcors" description:"Add an ip:port/hostname to allow cross origin access from. To allow all origins, set as \"*\"."` 252 Listeners []net.Addr 253 ExternalIPs []net.Addr 254 DisableListen bool `long:"nolisten" description:"Disable listening for incoming peer connections"` 255 DisableRest bool `long:"norest" description:"Disable REST API"` 256 DisableRestTLS bool `long:"no-rest-tls" description:"Disable TLS for REST connections"` 257 WSPingInterval time.Duration `long:"ws-ping-interval" description:"The ping interval for REST based WebSocket connections, set to 0 to disable sending ping messages from the server side"` 258 WSPongWait time.Duration `long:"ws-pong-wait" description:"The time we wait for a pong response message on REST based WebSocket connections before the connection is closed as inactive"` 259 NAT bool `long:"nat" description:"Toggle NAT traversal support (using either UPnP or NAT-PMP) to automatically advertise your external IP address to the network -- NOTE this does not support devices behind multiple NATs"` 260 MinBackoff time.Duration `long:"minbackoff" description:"Shortest backoff when reconnecting to persistent peers. Valid time units are {s, m, h}."` 261 MaxBackoff time.Duration `long:"maxbackoff" description:"Longest backoff when reconnecting to persistent peers. Valid time units are {s, m, h}."` 262 ConnectionTimeout time.Duration `long:"connectiontimeout" description:"The timeout value for network connections. Valid time units are {ms, s, m, h}."` 263 264 DebugLevel string `short:"d" long:"debuglevel" description:"Logging level for all subsystems {trace, debug, info, warn, error, critical} -- You may also specify <global-level>,<subsystem>=<level>,<subsystem2>=<level>,... to set the log level for individual subsystems -- Use show to list available subsystems"` 265 266 CPUProfile string `long:"cpuprofile" description:"Write CPU profile to the specified file"` 267 MemProfile string `long:"memprofile" description:"Write memory profile to the specified file"` 268 269 Profile string `long:"profile" description:"Enable HTTP profiling on either a port or host:port"` 270 271 UnsafeDisconnect bool `long:"unsafe-disconnect" description:"DEPRECATED: Allows the rpcserver to intentionally disconnect from peers with open channels. THIS FLAG WILL BE REMOVED IN THE FUTURE"` 272 UnsafeReplay bool `long:"unsafe-replay" description:"Causes a link to replay the adds on its commitment txn after starting up, this enables testing of the sphinx replay logic."` 273 MaxPendingChannels int `long:"maxpendingchannels" description:"The maximum number of incoming pending channels permitted per peer."` 274 BackupFilePath string `long:"backupfilepath" description:"The target location of the channel backup file"` 275 276 FeeURL string `long:"feeurl" description:"Optional URL for external fee estimation. If no URL is specified, the method for fee estimation will depend on the chosen backend and network."` 277 278 Decred *lncfg.Chain 279 DcrdMode *lncfg.DcrdConfig `group:"dcrd" namespace:"dcrd"` 280 Dcrwallet *lncfg.DcrwalletConfig `group:"dcrwallet" namespace:"dcrwallet"` 281 282 BlockCacheSize uint64 `long:"blockcachesize" description:"The maximum capacity of the block cache"` 283 284 Autopilot *lncfg.AutoPilot `group:"Autopilot" namespace:"autopilot"` 285 286 Automation *lncfg.Automation `group:"Automation" namespace:"automation"` 287 288 Tor *lncfg.Tor `group:"Tor" namespace:"tor"` 289 290 SubRPCServers *subRPCServerConfigs `group:"subrpc"` 291 292 Hodl *hodl.Config `group:"hodl" namespace:"hodl"` 293 294 NoNetBootstrap bool `long:"nobootstrap" description:"If true, then automatic network bootstrapping will not be attempted."` 295 296 NoSeedBackup bool `long:"noseedbackup" description:"If true, NO SEED WILL BE EXPOSED -- EVER, AND THE WALLET WILL BE ENCRYPTED USING THE DEFAULT PASSPHRASE. THIS FLAG IS ONLY FOR TESTING AND SHOULD NEVER BE USED ON MAINNET."` 297 WalletUnlockPasswordFile string `long:"wallet-unlock-password-file" description:"The full path to a file (or pipe/device) that contains the password for unlocking the wallet; if set, no unlocking through RPC is possible and lnd will exit if no wallet exists or the password is incorrect; if wallet-unlock-allow-create is also set then lnd will ignore this flag if no wallet exists and allow a wallet to be created through RPC."` 298 WalletUnlockAllowCreate bool `long:"wallet-unlock-allow-create" description:"Don't fail with an error if wallet-unlock-password-file is set but no wallet exists yet."` 299 300 resetWalletTransactions bool `long:"reset-wallet-transaction" description:"Not supported in dcrlnd"` 301 302 CoinSelectionStrategy string `long:"coin-selection-strategy" description:"The strategy to use for selecting coins for wallet transactions." choice:"random"` 303 304 PaymentsExpirationGracePeriod time.Duration `long:"payments-expiration-grace-period" description:"A period to wait before force closing channels with outgoing htlcs that have timed-out and are a result of this node initiated payments."` 305 TrickleDelay int `long:"trickledelay" description:"Time in milliseconds between each release of announcements to the network"` 306 ChanEnableTimeout time.Duration `long:"chan-enable-timeout" description:"The duration that a peer connection must be stable before attempting to send a channel update to reenable or cancel a pending disables of the peer's channels on the network."` 307 ChanDisableTimeout time.Duration `long:"chan-disable-timeout" description:"The duration that must elapse after first detecting that an already active channel is actually inactive and sending channel update disabling it to the network. The pending disable can be canceled if the peer reconnects and becomes stable for chan-enable-timeout before the disable update is sent."` 308 ChanStatusSampleInterval time.Duration `long:"chan-status-sample-interval" description:"The polling interval between attempts to detect if an active channel has become inactive due to its peer going offline."` 309 HeightHintCacheQueryDisable bool `long:"height-hint-cache-query-disable" description:"Disable queries from the height-hint cache to try to recover channels stuck in the pending close state. Disabling height hint queries may cause longer chain rescans, resulting in a performance hit. Unset this after channels are unstuck so you can get better performance again."` 310 Alias string `long:"alias" description:"The node alias. Used as a moniker by peers and intelligence services"` 311 Color string `long:"color" description:"The color of the node in hex format (i.e. '#3399FF'). Used to customize node appearance in intelligence services"` 312 MinChanSize int64 `long:"minchansize" description:"The smallest channel size (in atoms) that we should accept. Incoming channels smaller than this will be rejected"` 313 MaxChanSize int64 `long:"maxchansize" description:"The largest channel size (in atoms) that we should accept. Incoming channels larger than this will be rejected"` 314 CoopCloseTargetConfs uint32 `long:"coop-close-target-confs" description:"The target number of blocks that a cooperative channel close transaction should confirm in. This is used to estimate the fee to use as the lower bound during fee negotiation for the channel closure."` 315 316 ChannelCommitInterval time.Duration `long:"channel-commit-interval" description:"The maximum time that is allowed to pass between receiving a channel state update and signing the next commitment. Setting this to a longer duration allows for more efficient channel operations at the cost of latency."` 317 ChannelCommitBatchSize uint32 `long:"channel-commit-batch-size" description:"The maximum number of channel state updates that is accumulated before signing a new commitment."` 318 319 DefaultRemoteMaxHtlcs uint16 `long:"default-remote-max-htlcs" description:"The default max_htlc applied when opening or accepting channels. This value limits the number of concurrent HTLCs that the remote party can add to the commitment. The maximum possible value is 300."` 320 321 NumGraphSyncPeers int `long:"numgraphsyncpeers" description:"The number of peers that we should receive new graph updates from. This option can be tuned to save bandwidth for light clients or routing nodes."` 322 HistoricalSyncInterval time.Duration `long:"historicalsyncinterval" description:"The polling interval between historical graph sync attempts. Each historical graph sync attempt ensures we reconcile with the remote peer's graph from the genesis block."` 323 324 IgnoreHistoricalGossipFilters bool `long:"ignore-historical-gossip-filters" description:"If true, will not reply with historical data that matches the range specified by a remote peer's gossip_timestamp_filter. Doing so will result in lower memory and bandwidth requirements."` 325 326 RejectPush bool `long:"rejectpush" description:"If true, lnd will not accept channel opening requests with non-zero push amounts. This should prevent accidental pushes to merchant nodes."` 327 328 RejectHTLC bool `long:"rejecthtlc" description:"If true, lnd will not forward any HTLCs that are meant as onward payments. This option will still allow lnd to send HTLCs and receive HTLCs but lnd won't be used as a hop."` 329 330 StaggerInitialReconnect bool `long:"stagger-initial-reconnect" description:"If true, will apply a randomized staggering between 0s and 30s when reconnecting to persistent peers on startup. The first 10 reconnections will be attempted instantly, regardless of the flag's value"` 331 332 MaxOutgoingCltvExpiry uint32 `long:"max-cltv-expiry" description:"The maximum number of blocks funds could be locked up for when forwarding payments."` 333 334 MaxChannelFeeAllocation float64 `long:"max-channel-fee-allocation" description:"The maximum percentage of total funds that can be allocated to a channel's commitment fee. This only applies for the initiator of the channel. Valid values are within [0.1, 1]."` 335 336 MaxCommitFeeRateAnchors uint64 `long:"max-commit-fee-rate-anchors" description:"The maximum fee rate in sat/vbyte that will be used for commitments of channels of the anchors type. Must be large enough to ensure transaction propagation"` 337 338 DryRunMigration bool `long:"dry-run-migration" description:"If true, lnd will abort committing a migration if it would otherwise have been successful. This leaves the database unmodified, and still compatible with the previously active version of lnd."` 339 340 net tor.Net 341 342 EnableUpfrontShutdown bool `long:"enable-upfront-shutdown" description:"If true, option upfront shutdown script will be enabled. If peers that we open channels with support this feature, we will automatically set the script to which cooperative closes should be paid out to on channel open. This offers the partial protection of a channel peer disconnecting from us if cooperative close is attempted with a different script."` 343 344 AcceptKeySend bool `long:"accept-keysend" description:"If true, spontaneous payments through keysend will be accepted. [experimental]"` 345 346 AcceptAMP bool `long:"accept-amp" description:"If true, spontaneous payments via AMP will be accepted."` 347 348 KeysendHoldTime time.Duration `long:"keysend-hold-time" description:"If non-zero, keysend payments are accepted but not immediately settled. If the payment isn't settled manually after the specified time, it is canceled automatically. [experimental]"` 349 350 GcCanceledInvoicesOnStartup bool `long:"gc-canceled-invoices-on-startup" description:"If true, we'll attempt to garbage collect canceled invoices upon start."` 351 352 GcCanceledInvoicesOnTheFly bool `long:"gc-canceled-invoices-on-the-fly" description:"If true, we'll delete newly canceled invoices on the fly."` 353 354 DustThreshold uint64 `long:"dust-threshold" description:"Sets the dust sum threshold in satoshis for a channel after which dust HTLC's will be failed."` 355 356 Invoices *lncfg.Invoices `group:"invoices" namespace:"invoices"` 357 358 Routing *lncfg.Routing `group:"routing" namespace:"routing"` 359 360 Gossip *lncfg.Gossip `group:"gossip" namespace:"gossip"` 361 362 Workers *lncfg.Workers `group:"workers" namespace:"workers"` 363 364 Caches *lncfg.Caches `group:"caches" namespace:"caches"` 365 366 Prometheus lncfg.Prometheus `group:"prometheus" namespace:"prometheus"` 367 368 WtClient *lncfg.WtClient `group:"wtclient" namespace:"wtclient"` 369 370 Watchtower *lncfg.Watchtower `group:"watchtower" namespace:"watchtower"` 371 372 ProtocolOptions *lncfg.ProtocolOptions `group:"protocol" namespace:"protocol"` 373 374 AllowCircularRoute bool `long:"allow-circular-route" description:"If true, our node will allow htlc forwards that arrive and depart on the same channel."` 375 376 HealthChecks *lncfg.HealthCheckConfig `group:"healthcheck" namespace:"healthcheck"` 377 378 DB *lncfg.DB `group:"db" namespace:"db"` 379 380 Cluster *lncfg.Cluster `group:"cluster" namespace:"cluster"` 381 382 RPCMiddleware *lncfg.RPCMiddleware `group:"rpcmiddleware" namespace:"rpcmiddleware"` 383 384 // LogWriter is the root logger that all of the daemon's subloggers are 385 // hooked up to. 386 LogWriter *build.RotatingLogWriter 387 388 // registeredChains keeps track of all chains that have been registered 389 // with the daemon. 390 registeredChains *chainreg.ChainRegistry 391 392 // networkDir is the path to the directory of the currently active 393 // network. This path will hold the files related to each different 394 // network. 395 networkDir string 396 397 // ActiveNetParams contains parameters of the target chain. 398 ActiveNetParams chainreg.DecredNetParams 399 } 400 401 // DefaultConfig returns all default values for the Config struct. 402 func DefaultConfig() Config { 403 return Config{ 404 LndDir: DefaultLndDir, 405 ConfigFile: DefaultConfigFile, 406 DataDir: defaultDataDir, 407 DebugLevel: defaultLogLevel, 408 TLSCertPath: defaultTLSCertPath, 409 TLSKeyPath: defaultTLSKeyPath, 410 TLSCertDuration: defaultTLSCertDuration, 411 LetsEncryptDir: defaultLetsEncryptDir, 412 LetsEncryptListen: defaultLetsEncryptListen, 413 LogDir: defaultLogDir, 414 MaxLogFiles: defaultMaxLogFiles, 415 MaxLogFileSize: defaultMaxLogFileSize, 416 AcceptorTimeout: defaultAcceptorTimeout, 417 WSPingInterval: lnrpc.DefaultPingInterval, 418 WSPongWait: lnrpc.DefaultPongWait, 419 Decred: &lncfg.Chain{ 420 MinHTLCIn: chainreg.DefaultDecredMinHTLCInMAtoms, 421 MinHTLCOut: chainreg.DefaultDecredMinHTLCOutMAtoms, 422 BaseFee: chainreg.DefaultDecredBaseFeeMAtoms, 423 FeeRate: chainreg.DefaultDecredFeeRate, 424 TimeLockDelta: chainreg.DefaultDecredTimeLockDelta, 425 MaxLocalDelay: defaultMaxLocalCSVDelay, 426 Node: "dcrd", 427 }, 428 DcrdMode: &lncfg.DcrdConfig{ 429 RPCHost: defaultRPCHost, 430 RPCCert: defaultDcrdRPCCertFile, 431 }, 432 Dcrwallet: &lncfg.DcrwalletConfig{}, 433 BlockCacheSize: defaultBlockCacheSize, 434 UnsafeDisconnect: true, 435 MaxPendingChannels: lncfg.DefaultMaxPendingChannels, 436 NoSeedBackup: defaultNoSeedBackup, 437 MinBackoff: defaultMinBackoff, 438 MaxBackoff: defaultMaxBackoff, 439 ConnectionTimeout: tor.DefaultConnTimeout, 440 SubRPCServers: &subRPCServerConfigs{ 441 SignRPC: &signrpc.Config{}, 442 RouterRPC: routerrpc.DefaultConfig(), 443 }, 444 Autopilot: &lncfg.AutoPilot{ 445 MaxChannels: 5, 446 Allocation: 0.6, 447 MinChannelSize: int64(funding.MinChanFundingSize), 448 MaxChannelSize: int64(MaxFundingAmount), 449 MinConfs: 1, 450 ConfTarget: autopilot.DefaultConfTarget, 451 Heuristic: map[string]float64{ 452 "top_centrality": 1.0, 453 }, 454 }, 455 Automation: &lncfg.Automation{ 456 ForceCloseChanReestablishWait: 60 * 60 * 24 * 3, // 3 days 457 }, 458 PaymentsExpirationGracePeriod: defaultPaymentsExpirationGracePeriod, 459 TrickleDelay: defaultTrickleDelay, 460 ChanStatusSampleInterval: defaultChanStatusSampleInterval, 461 ChanEnableTimeout: defaultChanEnableTimeout, 462 ChanDisableTimeout: defaultChanDisableTimeout, 463 HeightHintCacheQueryDisable: defaultHeightHintCacheQueryDisable, 464 Alias: defaultAlias, 465 Color: defaultColor, 466 MinChanSize: int64(funding.MinChanFundingSize), 467 MaxChanSize: int64(0), 468 CoopCloseTargetConfs: defaultCoopCloseTargetConfs, 469 DefaultRemoteMaxHtlcs: defaultRemoteMaxHtlcs, 470 NumGraphSyncPeers: defaultMinPeers, 471 HistoricalSyncInterval: discovery.DefaultHistoricalSyncInterval, 472 Tor: &lncfg.Tor{ 473 SOCKS: defaultTorSOCKS, 474 DNS: defaultTorDNS, 475 Control: defaultTorControl, 476 }, 477 net: &tor.ClearNet{}, 478 Workers: &lncfg.Workers{ 479 Read: lncfg.DefaultReadWorkers, 480 Write: lncfg.DefaultWriteWorkers, 481 Sig: lncfg.DefaultSigWorkers, 482 }, 483 Caches: &lncfg.Caches{ 484 RejectCacheSize: channeldb.DefaultRejectCacheSize, 485 ChannelCacheSize: channeldb.DefaultChannelCacheSize, 486 }, 487 Prometheus: lncfg.DefaultPrometheus(), 488 Watchtower: &lncfg.Watchtower{ 489 TowerDir: defaultTowerDir, 490 }, 491 HealthChecks: &lncfg.HealthCheckConfig{ 492 ChainCheck: &lncfg.CheckConfig{ 493 Interval: defaultChainInterval, 494 Timeout: defaultChainTimeout, 495 Attempts: defaultChainAttempts, 496 Backoff: defaultChainBackoff, 497 }, 498 DiskCheck: &lncfg.DiskCheckConfig{ 499 RequiredRemaining: defaultRequiredDisk, 500 CheckConfig: &lncfg.CheckConfig{ 501 Interval: defaultDiskInterval, 502 Attempts: defaultDiskAttempts, 503 Timeout: defaultDiskTimeout, 504 Backoff: defaultDiskBackoff, 505 }, 506 }, 507 TLSCheck: &lncfg.CheckConfig{ 508 Interval: defaultTLSInterval, 509 Timeout: defaultTLSTimeout, 510 Attempts: defaultTLSAttempts, 511 Backoff: defaultTLSBackoff, 512 }, 513 TorConnection: &lncfg.CheckConfig{ 514 Interval: defaultTCInterval, 515 Timeout: defaultTCTimeout, 516 Attempts: defaultTCAttempts, 517 Backoff: defaultTCBackoff, 518 }, 519 }, 520 Routing: &lncfg.Routing{ 521 AssumeChannelValid: false, 522 }, 523 Gossip: &lncfg.Gossip{ 524 MaxChannelUpdateBurst: discovery.DefaultMaxChannelUpdateBurst, 525 ChannelUpdateInterval: discovery.DefaultChannelUpdateInterval, 526 }, 527 Invoices: &lncfg.Invoices{ 528 HoldExpiryDelta: lncfg.DefaultHoldInvoiceExpiryDelta, 529 }, 530 MaxOutgoingCltvExpiry: htlcswitch.DefaultMaxOutgoingCltvExpiry, 531 MaxChannelFeeAllocation: htlcswitch.DefaultMaxLinkFeeAllocation, 532 MaxCommitFeeRateAnchors: lnwallet.DefaultAnchorsCommitMaxFeeRateAtomsPerByte, 533 DustThreshold: uint64(htlcswitch.DefaultDustThreshold.ToAtoms()), 534 LogWriter: build.NewRotatingLogWriter(), 535 DB: lncfg.DefaultDB(), 536 Cluster: lncfg.DefaultCluster(), 537 RPCMiddleware: lncfg.DefaultRPCMiddleware(), 538 registeredChains: chainreg.NewChainRegistry(), 539 ActiveNetParams: chainreg.DecredTestNetParams, 540 ChannelCommitInterval: defaultChannelCommitInterval, 541 ChannelCommitBatchSize: defaultChannelCommitBatchSize, 542 CoinSelectionStrategy: defaultCoinSelectionStrategy, 543 } 544 } 545 546 // LoadConfig initializes and parses the config using a config file and command 547 // line options. 548 // 549 // The configuration proceeds as follows: 550 // 1. Start with a default config with sane settings 551 // 2. Pre-parse the command line to check for an alternative config file 552 // 3. Load configuration file overwriting defaults with any specified options 553 // 4. Parse CLI options and overwrite/add any specified options 554 func LoadConfig(interceptor signal.Interceptor) (*Config, error) { 555 // Pre-parse the command line options to pick up an alternative config 556 // file. 557 preCfg := DefaultConfig() 558 if _, err := flags.Parse(&preCfg); err != nil { 559 return nil, err 560 } 561 562 // Show the version and exit if the version flag was specified. 563 appName := filepath.Base(os.Args[0]) 564 appName = strings.TrimSuffix(appName, filepath.Ext(appName)) 565 usageMessage := fmt.Sprintf("Use %s -h to show usage", appName) 566 if preCfg.ShowVersion { 567 commit := build.SourceCommit() 568 if commit != "" { 569 commit = fmt.Sprintf("Commit %s; ", commit) 570 } 571 fmt.Printf("%s version %s (%sGo version %s %s/%s)\n", 572 appName, build.Version(), commit, 573 runtime.Version(), runtime.GOOS, runtime.GOARCH) 574 os.Exit(0) 575 } 576 577 // If the config file path has not been modified by the user, then we'll 578 // use the default config file path. However, if the user has modified 579 // their lnddir, then we should assume they intend to use the config 580 // file within it. 581 configFileDir := CleanAndExpandPath(preCfg.LndDir) 582 configFilePath := CleanAndExpandPath(preCfg.ConfigFile) 583 if configFileDir != DefaultLndDir { 584 if configFilePath == DefaultConfigFile { 585 configFilePath = filepath.Join( 586 configFileDir, lncfg.DefaultConfigFilename, 587 ) 588 } 589 } 590 591 // Next, load any additional configuration options from the file. 592 var configFileError error 593 cfg := preCfg 594 fileParser := flags.NewParser(&cfg, flags.Default) 595 err := flags.NewIniParser(fileParser).ParseFile(configFilePath) 596 if err != nil { 597 // If it's a parsing related error, then we'll return 598 // immediately, otherwise we can proceed as possibly the config 599 // file doesn't exist which is OK. 600 if _, ok := err.(*flags.IniError); ok { 601 return nil, err 602 } 603 604 configFileError = err 605 } 606 607 // Finally, parse the remaining command line options again to ensure 608 // they take precedence. 609 flagParser := flags.NewParser(&cfg, flags.Default) 610 if _, err := flagParser.Parse(); err != nil { 611 return nil, err 612 } 613 614 // Make sure everything we just loaded makes sense. 615 cleanCfg, err := ValidateConfig( 616 cfg, interceptor, fileParser, flagParser, 617 ) 618 if usageErr, ok := err.(*usageError); ok { 619 // The logging system might not yet be initialized, so we also 620 // write to stderr to make sure the error appears somewhere. 621 _, _ = fmt.Fprintln(os.Stderr, usageMessage) 622 ltndLog.Warnf("Incorrect usage: %v", usageMessage) 623 624 // The log subsystem might not yet be initialized. But we still 625 // try to log the error there since some packaging solutions 626 // might only look at the log and not stdout/stderr. 627 ltndLog.Warnf("Error validating config: %v", usageErr.err) 628 629 return nil, usageErr.err 630 } 631 if err != nil { 632 // The log subsystem might not yet be initialized. But we still 633 // try to log the error there since some packaging solutions 634 // might only look at the log and not stdout/stderr. 635 ltndLog.Warnf("Error validating config: %v", err) 636 637 return nil, err 638 } 639 640 // Warn about missing config file only after all other configuration is 641 // done. This prevents the warning on help messages and invalid options. 642 // Note this should go directly before the return. 643 if configFileError != nil { 644 ltndLog.Warnf("%v", configFileError) 645 } 646 647 return cleanCfg, nil 648 } 649 650 // usageError is an error type that signals a problem with the supplied flags. 651 type usageError struct { 652 err error 653 } 654 655 // Error returns the error string. 656 // 657 // NOTE: This is part of the error interface. 658 func (u *usageError) Error() string { 659 return u.err.Error() 660 } 661 662 // ValidateConfig check the given configuration to be sane. This makes sure no 663 // illegal values or combination of values are set. All file system paths are 664 // normalized. The cleaned up config is returned on success. 665 func ValidateConfig(cfg Config, interceptor signal.Interceptor, fileParser, 666 flagParser *flags.Parser) (*Config, error) { 667 668 // If the provided lnd directory is not the default, we'll modify the 669 // path to all of the files and directories that will live within it. 670 lndDir := CleanAndExpandPath(cfg.LndDir) 671 if lndDir != DefaultLndDir { 672 cfg.DataDir = filepath.Join(lndDir, defaultDataDirname) 673 cfg.LetsEncryptDir = filepath.Join( 674 lndDir, defaultLetsEncryptDirname, 675 ) 676 cfg.TLSCertPath = filepath.Join(lndDir, defaultTLSCertFilename) 677 cfg.TLSKeyPath = filepath.Join(lndDir, defaultTLSKeyFilename) 678 cfg.LogDir = filepath.Join(lndDir, defaultLogDirname) 679 680 // If the watchtower's directory is set to the default, i.e. the 681 // user has not requested a different location, we'll move the 682 // location to be relative to the specified lnd directory. 683 if cfg.Watchtower.TowerDir == defaultTowerDir { 684 cfg.Watchtower.TowerDir = filepath.Join( 685 cfg.DataDir, defaultTowerSubDirname, 686 ) 687 } 688 } 689 690 funcName := "ValidateConfig" 691 mkErr := func(format string, args ...interface{}) error { 692 return fmt.Errorf(funcName+": "+format, args...) 693 } 694 makeDirectory := func(dir string) error { 695 err := os.MkdirAll(dir, 0700) 696 if err != nil { 697 // Show a nicer error message if it's because a symlink 698 // is linked to a directory that does not exist 699 // (probably because it's not mounted). 700 if e, ok := err.(*os.PathError); ok && os.IsExist(err) { 701 link, lerr := os.Readlink(e.Path) 702 if lerr == nil { 703 str := "is symlink %s -> %s mounted?" 704 err = fmt.Errorf(str, e.Path, link) 705 } 706 } 707 708 str := "Failed to create lnd directory '%s': %v" 709 return mkErr(str, dir, err) 710 } 711 712 return nil 713 } 714 715 // IsSet returns true if an option has been set in either the config 716 // file or by a flag. 717 isSet := func(field string) (bool, error) { 718 fieldName, ok := reflect.TypeOf(Config{}).FieldByName(field) 719 if !ok { 720 str := "could not find field %s" 721 return false, mkErr(str, field) 722 } 723 724 long, ok := fieldName.Tag.Lookup("long") 725 if !ok { 726 str := "field %s does not have a long tag" 727 return false, mkErr(str, field) 728 } 729 730 // The user has the option to set the flag in either the config 731 // file or as a command line flag. If any is set, we consider it 732 // to be set, not applying any precedence rules here (since it 733 // is a boolean the default is false anyway which would screw up 734 // any precedence rules). Additionally, we need to also support 735 // the use case where the config struct is embedded _within_ 736 // another struct with a prefix (as is the case with 737 // lightning-terminal). 738 fileOption := fileParser.FindOptionByLongName(long) 739 fileOptionNested := fileParser.FindOptionByLongName( 740 "lnd." + long, 741 ) 742 flagOption := flagParser.FindOptionByLongName(long) 743 flagOptionNested := flagParser.FindOptionByLongName( 744 "lnd." + long, 745 ) 746 747 return (fileOption != nil && fileOption.IsSet()) || 748 (fileOptionNested != nil && fileOptionNested.IsSet()) || 749 (flagOption != nil && flagOption.IsSet()) || 750 (flagOptionNested != nil && flagOptionNested.IsSet()), 751 nil 752 } 753 754 // As soon as we're done parsing configuration options, ensure all paths 755 // to directories and files are cleaned and expanded before attempting 756 // to use them later on. 757 cfg.DataDir = CleanAndExpandPath(cfg.DataDir) 758 cfg.TLSCertPath = CleanAndExpandPath(cfg.TLSCertPath) 759 cfg.TLSKeyPath = CleanAndExpandPath(cfg.TLSKeyPath) 760 cfg.LetsEncryptDir = CleanAndExpandPath(cfg.LetsEncryptDir) 761 cfg.AdminMacPath = CleanAndExpandPath(cfg.AdminMacPath) 762 cfg.ReadMacPath = CleanAndExpandPath(cfg.ReadMacPath) 763 cfg.InvoiceMacPath = CleanAndExpandPath(cfg.InvoiceMacPath) 764 cfg.LogDir = CleanAndExpandPath(cfg.LogDir) 765 cfg.Tor.PrivateKeyPath = CleanAndExpandPath(cfg.Tor.PrivateKeyPath) 766 cfg.Tor.WatchtowerKeyPath = CleanAndExpandPath(cfg.Tor.WatchtowerKeyPath) 767 cfg.Watchtower.TowerDir = CleanAndExpandPath(cfg.Watchtower.TowerDir) 768 cfg.Dcrwallet.CertPath = CleanAndExpandPath(cfg.Dcrwallet.CertPath) 769 cfg.Dcrwallet.ClientKeyPath = CleanAndExpandPath(cfg.Dcrwallet.ClientKeyPath) 770 cfg.Dcrwallet.ClientCertPath = CleanAndExpandPath(cfg.Dcrwallet.ClientCertPath) 771 cfg.BackupFilePath = CleanAndExpandPath(cfg.BackupFilePath) 772 cfg.WalletUnlockPasswordFile = CleanAndExpandPath( 773 cfg.WalletUnlockPasswordFile, 774 ) 775 776 // Ensure that the user didn't attempt to specify negative values for 777 // any of the autopilot params. 778 if cfg.Autopilot.MaxChannels < 0 { 779 str := "autopilot.maxchannels must be non-negative" 780 return nil, mkErr(str) 781 } 782 if cfg.Autopilot.Allocation < 0 { 783 str := "autopilot.allocation must be non-negative" 784 return nil, mkErr(str) 785 } 786 if cfg.Autopilot.MinChannelSize < 0 { 787 str := "autopilot.minchansize must be non-negative" 788 return nil, mkErr(str) 789 } 790 if cfg.Autopilot.MaxChannelSize < 0 { 791 str := "autopilot.maxchansize must be non-negative" 792 return nil, mkErr(str) 793 } 794 if cfg.Autopilot.MinConfs < 0 { 795 str := "autopilot.minconfs must be non-negative" 796 return nil, mkErr(str) 797 } 798 if cfg.Autopilot.ConfTarget < 1 { 799 str := "autopilot.conftarget must be positive" 800 return nil, mkErr(str) 801 } 802 803 // Ensure that the specified values for the min and max channel size 804 // are within the bounds of the normal chan size constraints. 805 if cfg.Autopilot.MinChannelSize < int64(funding.MinChanFundingSize) { 806 cfg.Autopilot.MinChannelSize = int64(funding.MinChanFundingSize) 807 } 808 if cfg.Autopilot.MaxChannelSize > int64(MaxFundingAmount) { 809 cfg.Autopilot.MaxChannelSize = int64(MaxFundingAmount) 810 } 811 812 if _, err := validateAtplCfg(cfg.Autopilot); err != nil { 813 return nil, mkErr("error validating autopilot: %v", err) 814 } 815 816 // Ensure that --maxchansize is properly handled when set by user. For 817 // non-Wumbo channels this limit remains 1073741823 atoms by default as 818 // specified in BOLT-02. For wumbo channels this limit is 500e8 atoms 819 // (500 DCR). Always enforce --maxchansize explicitly set by user. If 820 // unset (marked by 0 value), then enforce proper default. 821 if cfg.MaxChanSize == 0 { 822 if cfg.ProtocolOptions.Wumbo() { 823 cfg.MaxChanSize = int64(funding.MaxDecredFundingAmountWumbo) 824 } else { 825 cfg.MaxChanSize = int64(funding.MaxDecredFundingAmount) 826 } 827 } 828 829 // Ensure that the user specified values for the min and max channel 830 // size make sense. 831 if cfg.MaxChanSize < cfg.MinChanSize { 832 return nil, mkErr("invalid channel size parameters: "+ 833 "max channel size %v, must be no less than min chan "+ 834 "size %v", cfg.MaxChanSize, cfg.MinChanSize, 835 ) 836 } 837 838 // Don't allow superflous --maxchansize greater than 839 // BOLT 02 soft-limit for non-wumbo channel 840 if !cfg.ProtocolOptions.Wumbo() && 841 cfg.MaxChanSize > int64(MaxFundingAmount) { 842 843 return nil, mkErr("invalid channel size parameters: "+ 844 "maximum channel size %v is greater than maximum "+ 845 "non-wumbo channel size %v", cfg.MaxChanSize, 846 MaxFundingAmount, 847 ) 848 } 849 850 // Ensure a valid max channel fee allocation was set. 851 if cfg.MaxChannelFeeAllocation <= 0 || cfg.MaxChannelFeeAllocation > 1 { 852 return nil, mkErr("invalid max channel fee allocation: %v, "+ 853 "must be within (0, 1]", cfg.MaxChannelFeeAllocation) 854 } 855 856 if cfg.MaxCommitFeeRateAnchors < 1 { 857 return nil, mkErr("invalid max commit fee rate anchors: %v, "+ 858 "must be at least 1 sat/vByte", 859 cfg.MaxCommitFeeRateAnchors) 860 } 861 862 // Validate the Tor config parameters. 863 socks, err := lncfg.ParseAddressString( 864 cfg.Tor.SOCKS, strconv.Itoa(defaultTorSOCKSPort), 865 cfg.net.ResolveTCPAddr, 866 ) 867 if err != nil { 868 return nil, err 869 } 870 cfg.Tor.SOCKS = socks.String() 871 872 // We'll only attempt to normalize and resolve the DNS host if it hasn't 873 // changed, as it doesn't need to be done for the default. 874 if cfg.Tor.DNS != defaultTorDNS { 875 dns, err := lncfg.ParseAddressString( 876 cfg.Tor.DNS, strconv.Itoa(defaultTorDNSPort), 877 cfg.net.ResolveTCPAddr, 878 ) 879 if err != nil { 880 return nil, mkErr("error parsing tor dns: %v", err) 881 } 882 cfg.Tor.DNS = dns.String() 883 } 884 885 control, err := lncfg.ParseAddressString( 886 cfg.Tor.Control, strconv.Itoa(defaultTorControlPort), 887 cfg.net.ResolveTCPAddr, 888 ) 889 if err != nil { 890 return nil, mkErr("error parsing tor control address: %v", err) 891 } 892 cfg.Tor.Control = control.String() 893 894 // Ensure that tor socks host:port is not equal to tor control 895 // host:port. This would lead to lnd not starting up properly. 896 if cfg.Tor.SOCKS == cfg.Tor.Control { 897 str := "tor.socks and tor.control can not us the same host:port" 898 return nil, mkErr(str) 899 } 900 901 switch { 902 case cfg.Tor.V2 && cfg.Tor.V3: 903 return nil, mkErr("either tor.v2 or tor.v3 can be set, " + 904 "but not both") 905 case cfg.DisableListen && (cfg.Tor.V2 || cfg.Tor.V3): 906 return nil, mkErr("listening must be enabled when enabling " + 907 "inbound connections over Tor") 908 } 909 910 if cfg.Tor.PrivateKeyPath == "" { 911 switch { 912 case cfg.Tor.V2: 913 cfg.Tor.PrivateKeyPath = filepath.Join( 914 lndDir, defaultTorV2PrivateKeyFilename, 915 ) 916 case cfg.Tor.V3: 917 cfg.Tor.PrivateKeyPath = filepath.Join( 918 lndDir, defaultTorV3PrivateKeyFilename, 919 ) 920 } 921 } 922 923 if cfg.Tor.WatchtowerKeyPath == "" { 924 switch { 925 case cfg.Tor.V2: 926 cfg.Tor.WatchtowerKeyPath = filepath.Join( 927 cfg.Watchtower.TowerDir, 928 defaultTorV2PrivateKeyFilename, 929 ) 930 case cfg.Tor.V3: 931 cfg.Tor.WatchtowerKeyPath = filepath.Join( 932 cfg.Watchtower.TowerDir, 933 defaultTorV3PrivateKeyFilename, 934 ) 935 } 936 } 937 938 // Set up the network-related functions that will be used throughout 939 // the daemon. We use the standard Go "net" package functions by 940 // default. If we should be proxying all traffic through Tor, then 941 // we'll use the Tor proxy specific functions in order to avoid leaking 942 // our real information. 943 if cfg.Tor.Active { 944 cfg.net = &tor.ProxyNet{ 945 SOCKS: cfg.Tor.SOCKS, 946 DNS: cfg.Tor.DNS, 947 StreamIsolation: cfg.Tor.StreamIsolation, 948 SkipProxyForClearNetTargets: cfg.Tor.SkipProxyForClearNetTargets, 949 } 950 } 951 952 if cfg.DisableListen && cfg.NAT { 953 return nil, mkErr("NAT traversal cannot be used when " + 954 "listening is disabled") 955 } 956 if cfg.NAT && len(cfg.ExternalHosts) != 0 { 957 return nil, mkErr("NAT support and externalhosts are " + 958 "mutually exclusive, only one should be selected") 959 } 960 961 // Multiple networks can't be selected simultaneously. Count number of 962 // network flags passed; assign active network params while we're at 963 // it. 964 numNets := 0 965 if cfg.Decred.TestNet3 { 966 numNets++ 967 cfg.ActiveNetParams = chainreg.DecredTestNetParams 968 } 969 if cfg.Decred.RegTest { 970 numNets++ 971 cfg.ActiveNetParams = chainreg.RegTestNetParams 972 } 973 if cfg.Decred.SimNet { 974 numNets++ 975 cfg.ActiveNetParams = chainreg.DecredSimNetParams 976 } 977 if numNets > 1 { 978 return nil, mkErr("%s: The testnet, regtest, and simnet params"+ 979 "can't be used together -- choose one of the three", 980 funcName) 981 } 982 983 // We default to mainnet if none are specified. 984 if numNets == 0 { 985 cfg.ActiveNetParams = chainreg.DecredMainNetParams 986 } 987 988 err = cfg.Decred.Validate(minTimeLockDelta, funding.MinDcrRemoteDelay) 989 if err != nil { 990 return nil, err 991 } 992 993 switch cfg.Decred.Node { 994 case "dcrd": 995 err := parseRPCParams( 996 cfg.Decred, cfg.DcrdMode, chainreg.DecredChain, 997 cfg.ActiveNetParams, 998 ) 999 if err != nil { 1000 err := fmt.Errorf("unable to load RPC "+ 1001 "credentials for dcrd: %v", err) 1002 return nil, err 1003 } 1004 case "dcrw": 1005 // In dcrw mode we use the underlying wallet for chain 1006 // operations. 1007 case "nochainbackend": 1008 // No chain sync. 1009 default: 1010 str := "%s: only dcrd and dcrw modes supported for Decred at " + 1011 "this time" 1012 return nil, fmt.Errorf(str, funcName) 1013 } 1014 1015 cfg.Decred.ChainDir = filepath.Join(cfg.DataDir, 1016 defaultChainSubDirname, 1017 chainreg.DecredChain.String()) 1018 1019 // Ensure sane config when using a remote wallet. 1020 if cfg.Dcrwallet.GRPCHost != "" { 1021 // Update Dcrwallet.GRPCHost with correct port from 1022 // activeNetParam selected. 1023 _, _, err := net.SplitHostPort(cfg.Dcrwallet.GRPCHost) 1024 if err != nil { 1025 cfg.Dcrwallet.GRPCHost = net.JoinHostPort( 1026 cfg.Dcrwallet.GRPCHost, 1027 cfg.ActiveNetParams.DcrwPort, 1028 ) 1029 } 1030 1031 // dcrwallet v1.6.0+ requires a client cert and key for gRPC 1032 // auth, so if any of {ClientKeyPath, ClientCertPath} are 1033 // specified, *both* need to be. 1034 // 1035 // Otherwise, the client key and cert will come on a 1036 // WalletUnlocker.Unlock() call. 1037 clientKeyEmpty := cfg.Dcrwallet.ClientKeyPath == "" 1038 clientCertEmpty := cfg.Dcrwallet.ClientCertPath == "" 1039 if clientKeyEmpty != clientCertEmpty { 1040 str := "%s: dcrwallet.clientkeypath and clientcertpath must both be specified" 1041 err := fmt.Errorf(str, funcName) 1042 return nil, err 1043 } 1044 } 1045 1046 // Finally we'll register the decred chain as our current 1047 // primary chain. 1048 cfg.registeredChains.RegisterPrimaryChain(chainreg.DecredChain) 1049 1050 // Ensure that the user didn't attempt to specify negative values for 1051 // any of the autopilot params. 1052 if cfg.Autopilot.MaxChannels < 0 { 1053 str := "autopilot.maxchannels must be non-negative" 1054 return nil, mkErr(str) 1055 } 1056 if cfg.Autopilot.Allocation < 0 { 1057 str := "autopilot.allocation must be non-negative" 1058 return nil, mkErr(str) 1059 } 1060 if cfg.Autopilot.MinChannelSize < 0 { 1061 str := "autopilot.minchansize must be non-negative" 1062 return nil, mkErr(str) 1063 } 1064 if cfg.Autopilot.MaxChannelSize < 0 { 1065 str := "autopilot.maxchansize must be non-negative" 1066 return nil, mkErr(str) 1067 } 1068 1069 // Ensure that the specified values for the min and max channel size 1070 // don't are within the bounds of the normal chan size constraints. 1071 if cfg.Autopilot.MinChannelSize < int64(funding.MinChanFundingSize) { 1072 cfg.Autopilot.MinChannelSize = int64(funding.MinChanFundingSize) 1073 } 1074 if cfg.Autopilot.MaxChannelSize > int64(MaxFundingAmount) { 1075 cfg.Autopilot.MaxChannelSize = int64(MaxFundingAmount) 1076 } 1077 1078 // Validate profile port or host:port. 1079 if cfg.Profile != "" { 1080 str := "%s: The profile port must be between 1024 and 65535" 1081 1082 // Try to parse Profile as a host:port. 1083 _, hostPort, err := net.SplitHostPort(cfg.Profile) 1084 if err == nil { 1085 // Determine if the port is valid. 1086 profilePort, err := strconv.Atoi(hostPort) 1087 if err != nil || profilePort < 1024 || profilePort > 65535 { 1088 return nil, &usageError{mkErr(str)} 1089 } 1090 } else { 1091 // Try to parse Profile as a port. 1092 profilePort, err := strconv.Atoi(cfg.Profile) 1093 if err != nil || profilePort < 1024 || profilePort > 65535 { 1094 return nil, &usageError{mkErr(str)} 1095 } 1096 1097 // Since the user just set a port, we will serve debugging 1098 // information over localhost. 1099 cfg.Profile = net.JoinHostPort("127.0.0.1", cfg.Profile) 1100 } 1101 } 1102 1103 // We'll now construct the network directory which will be where we 1104 // store all the data specific to this chain/network. 1105 cfg.networkDir = filepath.Join( 1106 cfg.DataDir, defaultChainSubDirname, 1107 cfg.registeredChains.PrimaryChain().String(), 1108 lncfg.NormalizeNetwork(cfg.ActiveNetParams.Name), 1109 ) 1110 1111 // If a custom macaroon directory wasn't specified and the data 1112 // directory has changed from the default path, then we'll also update 1113 // the path for the macaroons to be generated. 1114 if cfg.AdminMacPath == "" { 1115 cfg.AdminMacPath = filepath.Join( 1116 cfg.networkDir, defaultAdminMacFilename, 1117 ) 1118 } 1119 if cfg.ReadMacPath == "" { 1120 cfg.ReadMacPath = filepath.Join( 1121 cfg.networkDir, defaultReadMacFilename, 1122 ) 1123 } 1124 if cfg.InvoiceMacPath == "" { 1125 cfg.InvoiceMacPath = filepath.Join( 1126 cfg.networkDir, defaultInvoiceMacFilename, 1127 ) 1128 } 1129 1130 // Create the lnd directory and all other sub-directories if they don't 1131 // already exist. This makes sure that directory trees are also created 1132 // for files that point to outside the lnddir. 1133 dirs := []string{ 1134 lndDir, cfg.DataDir, cfg.networkDir, 1135 cfg.LetsEncryptDir, cfg.Watchtower.TowerDir, 1136 filepath.Dir(cfg.TLSCertPath), filepath.Dir(cfg.TLSKeyPath), 1137 filepath.Dir(cfg.AdminMacPath), filepath.Dir(cfg.ReadMacPath), 1138 filepath.Dir(cfg.InvoiceMacPath), 1139 filepath.Dir(cfg.Tor.PrivateKeyPath), 1140 filepath.Dir(cfg.Tor.WatchtowerKeyPath), 1141 } 1142 for _, dir := range dirs { 1143 if err := makeDirectory(dir); err != nil { 1144 return nil, err 1145 } 1146 } 1147 1148 // Similarly, if a custom back up file path wasn't specified, then 1149 // we'll update the file location to match our set network directory. 1150 if cfg.BackupFilePath == "" { 1151 cfg.BackupFilePath = filepath.Join( 1152 cfg.networkDir, chanbackup.DefaultBackupFileName, 1153 ) 1154 } 1155 1156 // Append the network type to the log directory so it is "namespaced" 1157 // per network in the same fashion as the data directory. 1158 cfg.LogDir = filepath.Join( 1159 cfg.LogDir, cfg.registeredChains.PrimaryChain().String(), 1160 lncfg.NormalizeNetwork(cfg.ActiveNetParams.Name), 1161 ) 1162 1163 // A log writer must be passed in, otherwise we can't function and would 1164 // run into a panic later on. 1165 if cfg.LogWriter == nil { 1166 return nil, mkErr("log writer missing in config") 1167 } 1168 1169 // Special show command to list supported subsystems and exit. 1170 if cfg.DebugLevel == "show" { 1171 fmt.Println("Supported subsystems", 1172 cfg.LogWriter.SupportedSubsystems()) 1173 os.Exit(0) 1174 } 1175 1176 // Initialize logging at the default logging level. 1177 SetupLoggers(cfg.LogWriter, interceptor) 1178 err = cfg.LogWriter.InitLogRotator( 1179 filepath.Join(cfg.LogDir, defaultLogFilename), 1180 cfg.MaxLogFileSize, cfg.MaxLogFiles, 1181 ) 1182 if err != nil { 1183 str := "log rotation setup failed: %v" 1184 return nil, mkErr(str, err) 1185 } 1186 1187 // Parse, validate, and set debug log level(s). 1188 err = build.ParseAndSetDebugLevels(cfg.DebugLevel, cfg.LogWriter) 1189 if err != nil { 1190 str := "error parsing debug level: %v" 1191 return nil, &usageError{mkErr(str, err)} 1192 } 1193 1194 // At least one RPCListener is required. So listen on localhost per 1195 // default. 1196 if len(cfg.RawRPCListeners) == 0 { 1197 addr := fmt.Sprintf("localhost:%d", defaultRPCPort) 1198 cfg.RawRPCListeners = append(cfg.RawRPCListeners, addr) 1199 } 1200 1201 // Listen on localhost if no REST listeners were specified. 1202 if len(cfg.RawRESTListeners) == 0 { 1203 addr := fmt.Sprintf("localhost:%d", defaultRESTPort) 1204 cfg.RawRESTListeners = append(cfg.RawRESTListeners, addr) 1205 } 1206 1207 // Listen on the default interface/port if no listeners were specified. 1208 // An empty address string means default interface/address, which on 1209 // most unix systems is the same as 0.0.0.0. If Tor is active, we 1210 // default to only listening on localhost for hidden service 1211 // connections. 1212 if len(cfg.RawListeners) == 0 { 1213 addr := fmt.Sprintf(":%d", defaultPeerPort) 1214 if cfg.Tor.Active && !cfg.Tor.SkipProxyForClearNetTargets { 1215 addr = fmt.Sprintf("localhost:%d", defaultPeerPort) 1216 } 1217 cfg.RawListeners = append(cfg.RawListeners, addr) 1218 } 1219 1220 // Add default port to all RPC listener addresses if needed and remove 1221 // duplicate addresses. 1222 cfg.RPCListeners, err = lncfg.NormalizeAddresses( 1223 cfg.RawRPCListeners, strconv.Itoa(defaultRPCPort), 1224 cfg.net.ResolveTCPAddr, 1225 ) 1226 if err != nil { 1227 return nil, mkErr("error normalizing RPC listen addrs: %v", err) 1228 } 1229 1230 // Add default port to all REST listener addresses if needed and remove 1231 // duplicate addresses. 1232 cfg.RESTListeners, err = lncfg.NormalizeAddresses( 1233 cfg.RawRESTListeners, strconv.Itoa(defaultRESTPort), 1234 cfg.net.ResolveTCPAddr, 1235 ) 1236 if err != nil { 1237 return nil, mkErr("error normalizing REST listen addrs: %v", err) 1238 } 1239 1240 switch { 1241 // The no seed backup and auto unlock are mutually exclusive. 1242 case cfg.NoSeedBackup && cfg.WalletUnlockPasswordFile != "": 1243 return nil, mkErr("cannot set noseedbackup and " + 1244 "wallet-unlock-password-file at the same time") 1245 1246 // The "allow-create" flag cannot be set without the auto unlock file. 1247 case cfg.WalletUnlockAllowCreate && cfg.WalletUnlockPasswordFile == "": 1248 return nil, mkErr("cannot set wallet-unlock-allow-create " + 1249 "without wallet-unlock-password-file") 1250 1251 // If a password file was specified, we need it to exist. 1252 case cfg.WalletUnlockPasswordFile != "" && 1253 !lnrpc.FileExists(cfg.WalletUnlockPasswordFile): 1254 1255 return nil, mkErr("wallet unlock password file %s does "+ 1256 "not exist", cfg.WalletUnlockPasswordFile) 1257 } 1258 1259 // For each of the RPC listeners (REST+gRPC), we'll ensure that users 1260 // have specified a safe combo for authentication. If not, we'll bail 1261 // out with an error. Since we don't allow disabling TLS for gRPC 1262 // connections we pass in tlsActive=true. 1263 err = lncfg.EnforceSafeAuthentication( 1264 cfg.RPCListeners, !cfg.NoMacaroons, true, 1265 ) 1266 if err != nil { 1267 return nil, mkErr("error enforcing safe authentication on "+ 1268 "RPC ports: %v", err) 1269 } 1270 1271 if cfg.DisableRest { 1272 ltndLog.Infof("REST API is disabled!") 1273 cfg.RESTListeners = nil 1274 } else { 1275 err = lncfg.EnforceSafeAuthentication( 1276 cfg.RESTListeners, !cfg.NoMacaroons, !cfg.DisableRestTLS, 1277 ) 1278 if err != nil { 1279 return nil, mkErr("error enforcing safe "+ 1280 "authentication on REST ports: %v", err) 1281 } 1282 } 1283 1284 // Remove the listening addresses specified if listening is disabled. 1285 if cfg.DisableListen { 1286 ltndLog.Infof("Listening on the p2p interface is disabled!") 1287 cfg.Listeners = nil 1288 cfg.ExternalIPs = nil 1289 } else { 1290 1291 // Add default port to all listener addresses if needed and remove 1292 // duplicate addresses. 1293 cfg.Listeners, err = lncfg.NormalizeAddresses( 1294 cfg.RawListeners, strconv.Itoa(defaultPeerPort), 1295 cfg.net.ResolveTCPAddr, 1296 ) 1297 if err != nil { 1298 return nil, mkErr("error normalizing p2p listen "+ 1299 "addrs: %v", err) 1300 } 1301 1302 // Add default port to all external IP addresses if needed and remove 1303 // duplicate addresses. 1304 cfg.ExternalIPs, err = lncfg.NormalizeAddresses( 1305 cfg.RawExternalIPs, strconv.Itoa(defaultPeerPort), 1306 cfg.net.ResolveTCPAddr, 1307 ) 1308 if err != nil { 1309 return nil, err 1310 } 1311 1312 // For the p2p port it makes no sense to listen to an Unix socket. 1313 // Also, we would need to refactor the brontide listener to support 1314 // that. 1315 for _, p2pListener := range cfg.Listeners { 1316 if lncfg.IsUnix(p2pListener) { 1317 return nil, mkErr("unix socket addresses "+ 1318 "cannot be used for the p2p "+ 1319 "connection listener: %s", p2pListener) 1320 } 1321 } 1322 } 1323 1324 // Ensure that the specified minimum backoff is below or equal to the 1325 // maximum backoff. 1326 if cfg.MinBackoff > cfg.MaxBackoff { 1327 return nil, mkErr("maxbackoff must be greater than minbackoff") 1328 } 1329 1330 // Newer versions of lnd added a new sub-config for bolt-specific 1331 // parameters. However, we want to also allow existing users to use the 1332 // value on the top-level config. If the outer config value is set, 1333 // then we'll use that directly. 1334 flagSet, err := isSet("SyncFreelist") 1335 if err != nil { 1336 return nil, mkErr("error parsing freelist sync flag: %v", err) 1337 } 1338 if flagSet { 1339 cfg.DB.Bolt.NoFreelistSync = !cfg.SyncFreelist 1340 } 1341 1342 // Ensure that the user hasn't chosen a remote-max-htlc value greater 1343 // than the protocol maximum. 1344 maxRemoteHtlcs := uint16(input.MaxHTLCNumber / 2) 1345 if cfg.DefaultRemoteMaxHtlcs > maxRemoteHtlcs { 1346 return nil, mkErr("default-remote-max-htlcs (%v) must be "+ 1347 "less than %v", cfg.DefaultRemoteMaxHtlcs, 1348 maxRemoteHtlcs) 1349 } 1350 1351 // Enforce only bbolt is being used in mainnet for now. 1352 if cfg.ActiveNetParams.Net == wire.MainNet && cfg.DB.Backend != lncfg.BoltBackend { 1353 return nil, fmt.Errorf("Cannot use DB backend %q in mainnet", 1354 cfg.DB.Backend) 1355 } 1356 1357 // Enforce anchors are not used in mainnet. 1358 if cfg.ActiveNetParams.Net == wire.MainNet && !cfg.ProtocolOptions.NoAnchorCommitments() { 1359 return nil, fmt.Errorf("cannot use anchor commitments on mainnet") 1360 } 1361 1362 if err := cfg.Gossip.Parse(); err != nil { 1363 return nil, mkErr("error parsing gossip syncer: %v", err) 1364 } 1365 1366 // Log a warning if our expiry delta is not greater than our incoming 1367 // broadcast delta. We do not fail here because this value may be set 1368 // to zero to intentionally keep lnd's behavior unchanged from when we 1369 // didn't auto-cancel these invoices. 1370 if cfg.Invoices.HoldExpiryDelta <= lncfg.DefaultIncomingBroadcastDelta { 1371 ltndLog.Warnf("Invoice hold expiry delta: %v <= incoming "+ 1372 "delta: %v, accepted hold invoices will force close "+ 1373 "channels if they are not canceled manually", 1374 cfg.Invoices.HoldExpiryDelta, 1375 lncfg.DefaultIncomingBroadcastDelta) 1376 } 1377 1378 // Validate the subconfigs for workers, caches, and the tower client. 1379 err = lncfg.Validate( 1380 cfg.Workers, 1381 cfg.Caches, 1382 cfg.WtClient, 1383 cfg.DB, 1384 cfg.Cluster, 1385 cfg.HealthChecks, 1386 cfg.RPCMiddleware, 1387 ) 1388 if err != nil { 1389 return nil, err 1390 } 1391 1392 // Finally, ensure that the user's color is correctly formatted, 1393 // otherwise the server will not be able to start after the unlocking 1394 // the wallet. 1395 _, err = parseHexColor(cfg.Color) 1396 if err != nil { 1397 return nil, mkErr("unable to parse node color: %v", err) 1398 } 1399 1400 // All good, return the sanitized result. 1401 return &cfg, nil 1402 } 1403 1404 // graphDatabaseDir returns the default directory where the local bolt graph db 1405 // files are stored. 1406 func (c *Config) graphDatabaseDir() string { 1407 return filepath.Join( 1408 c.DataDir, defaultGraphSubDirname, 1409 lncfg.NormalizeNetwork(c.ActiveNetParams.Name), 1410 ) 1411 } 1412 1413 // ImplementationConfig returns the configuration of what actual implementations 1414 // should be used when creating the main lnd instance. 1415 func (c *Config) ImplementationConfig( 1416 interceptor signal.Interceptor) *ImplementationCfg { 1417 1418 defaultImpl := NewDefaultWalletImpl(c, ltndLog, interceptor) 1419 1420 // Switch to remote wallet mode if needed. 1421 var chainCC ChainControlBuilder = defaultImpl 1422 if c.Dcrwallet.GRPCHost != "" && c.Dcrwallet.CertPath != "" { 1423 chainCC = &RemoteWalletBuilder{logger: ltndLog} 1424 } 1425 1426 return &ImplementationCfg{ 1427 GrpcRegistrar: defaultImpl, 1428 RestRegistrar: defaultImpl, 1429 ExternalValidator: defaultImpl, 1430 DatabaseBuilder: NewDefaultDatabaseBuilder(c, ltndLog), 1431 WalletConfigBuilder: defaultImpl, 1432 ChainControlBuilder: chainCC, 1433 } 1434 } 1435 1436 // CleanAndExpandPath expands environment variables and leading ~ in the 1437 // passed path, cleans the result, and returns it. 1438 // This function is taken from https://github.com/decred/dcrd 1439 func CleanAndExpandPath(path string) string { 1440 if path == "" { 1441 return "" 1442 } 1443 1444 // Expand initial ~ to OS specific home directory. 1445 if strings.HasPrefix(path, "~") { 1446 var homeDir string 1447 u, err := user.Current() 1448 if err == nil { 1449 homeDir = u.HomeDir 1450 } else { 1451 homeDir = os.Getenv("HOME") 1452 } 1453 1454 path = strings.Replace(path, "~", homeDir, 1) 1455 } 1456 1457 // NOTE: The os.ExpandEnv doesn't work with Windows-style %VARIABLE%, 1458 // but the variables can still be expanded via POSIX-style $VARIABLE. 1459 return filepath.Clean(os.ExpandEnv(path)) 1460 } 1461 1462 func parseRPCParams(cConfig *lncfg.Chain, nodeConfig interface{}, 1463 net chainreg.ChainCode, netParams chainreg.DecredNetParams) error { 1464 1465 // First, we'll check our node config to make sure the RPC parameters 1466 // were set correctly. We'll also determine the path to the conf file 1467 // depending on the backend node. 1468 var daemonName, confDir, confFile string 1469 switch conf := nodeConfig.(type) { 1470 case *lncfg.DcrdConfig: 1471 // If both RPCUser and RPCPass are set, we assume those 1472 // credentials are good to use. 1473 if conf.RPCUser != "" && conf.RPCPass != "" { 1474 return nil 1475 } 1476 1477 // Get the daemon name for displaying proper errors. 1478 switch net { 1479 case chainreg.DecredChain: 1480 daemonName = "dcrd" 1481 confFile = "dcrd" 1482 } 1483 1484 // If only ONE of RPCUser or RPCPass is set, we assume the 1485 // user did that unintentionally. 1486 if conf.RPCUser != "" || conf.RPCPass != "" { 1487 return fmt.Errorf("please set both or neither of "+ 1488 "%[1]v.rpcuser, %[1]v.rpcpass", daemonName) 1489 } 1490 } 1491 1492 // If we're in simnet mode, then the running dcrd instance won't read 1493 // the RPC credentials from the configuration. So if lnd wasn't 1494 // specified the parameters, then we won't be able to start. 1495 if cConfig.SimNet { 1496 return fmt.Errorf("rpcuser and rpcpass must be set to your " + 1497 "dcrd node's RPC parameters for simnet mode") 1498 } 1499 1500 fmt.Println("Attempting automatic RPC configuration to " + daemonName) 1501 1502 confFile = filepath.Join(confDir, fmt.Sprintf("%v.conf", confFile)) 1503 switch cConfig.Node { 1504 case "dcrd": 1505 nConf := nodeConfig.(*lncfg.DcrdConfig) 1506 rpcUser, rpcPass, err := extractDcrdRPCParams(confFile) 1507 if err != nil { 1508 return fmt.Errorf("unable to extract RPC credentials: "+ 1509 "%v, cannot start w/o RPC connection", err) 1510 } 1511 nConf.RPCUser, nConf.RPCPass = rpcUser, rpcPass 1512 } 1513 1514 fmt.Printf("Automatically obtained %v's RPC credentials\n", daemonName) 1515 return nil 1516 } 1517 1518 // extractDcrdRPCParams attempts to extract the RPC credentials for an existing 1519 // dcrd instance. The passed path is expected to be the location of dcrd's 1520 // application data directory on the target system. 1521 func extractDcrdRPCParams(dcrdConfigPath string) (string, string, error) { 1522 // First, we'll open up the dcrd configuration file found at the target 1523 // destination. 1524 dcrdConfigFile, err := os.Open(dcrdConfigPath) 1525 if err != nil { 1526 return "", "", err 1527 } 1528 defer dcrdConfigFile.Close() 1529 1530 // With the file open extract the contents of the configuration file so 1531 // we can attempt to locate the RPC credentials. 1532 configContents, err := ioutil.ReadAll(dcrdConfigFile) 1533 if err != nil { 1534 return "", "", err 1535 } 1536 1537 // Attempt to locate the RPC user using a regular expression. If we 1538 // don't have a match for our regular expression then we'll exit with 1539 // an error. 1540 rpcUserRegexp, err := regexp.Compile(`(?m)^\s*rpcuser\s*=\s*([^\s]+)`) 1541 if err != nil { 1542 return "", "", err 1543 } 1544 userSubmatches := rpcUserRegexp.FindSubmatch(configContents) 1545 if userSubmatches == nil { 1546 return "", "", fmt.Errorf("unable to find rpcuser in config") 1547 } 1548 1549 // Similarly, we'll use another regular expression to find the set 1550 // rpcpass (if any). If we can't find the pass, then we'll exit with an 1551 // error. 1552 rpcPassRegexp, err := regexp.Compile(`(?m)^\s*rpcpass\s*=\s*([^\s]+)`) 1553 if err != nil { 1554 return "", "", err 1555 } 1556 passSubmatches := rpcPassRegexp.FindSubmatch(configContents) 1557 if passSubmatches == nil { 1558 return "", "", fmt.Errorf("unable to find rpcuser in config") 1559 } 1560 1561 return string(userSubmatches[1]), string(passSubmatches[1]), nil 1562 }