Merge pull request #4286 from guggero/remove-global-cfg

multi: remove global cfg variable
This commit is contained in:
Olaoluwa Osuntokun 2020-05-18 19:45:43 -07:00 committed by GitHub
commit c2516d9352
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 655 additions and 418 deletions

View File

@ -28,6 +28,7 @@ import (
"github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
@ -160,7 +161,7 @@ type chainControl struct {
// full-node, another backed by a running bitcoind full-node, and the other
// backed by a running neutrino light client instance. When running with a
// neutrino light client instance, `neutrinoCS` must be non-nil.
func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
func newChainControlFromConfig(cfg *Config, chanDB *channeldb.DB,
privateWalletPw, publicWalletPw []byte, birthday time.Time,
recoveryWindow uint32, wallet *wallet.Wallet,
neutrinoCS *neutrino.ChainService) (*chainControl, error) {
@ -168,15 +169,15 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
// Set the RPC config from the "home" chain. Multi-chain isn't yet
// active, so we'll restrict usage to a particular chain for now.
homeChainConfig := cfg.Bitcoin
if registeredChains.PrimaryChain() == litecoinChain {
if cfg.registeredChains.PrimaryChain() == litecoinChain {
homeChainConfig = cfg.Litecoin
}
ltndLog.Infof("Primary chain is set to: %v",
registeredChains.PrimaryChain())
cfg.registeredChains.PrimaryChain())
cc := &chainControl{}
switch registeredChains.PrimaryChain() {
switch cfg.registeredChains.PrimaryChain() {
case bitcoinChain:
cc.routingPolicy = htlcswitch.ForwardingPolicy{
MinHTLCOut: cfg.Bitcoin.MinHTLCOut,
@ -202,7 +203,7 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
)
default:
return nil, fmt.Errorf("default routing policy for chain %v is "+
"unknown", registeredChains.PrimaryChain())
"unknown", cfg.registeredChains.PrimaryChain())
}
walletConfig := &btcwallet.Config{
@ -263,7 +264,7 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
)
case "bitcoind", "litecoind":
var bitcoindMode *bitcoindConfig
var bitcoindMode *lncfg.Bitcoind
switch {
case cfg.Bitcoin.Active:
bitcoindMode = cfg.BitcoindMode
@ -388,7 +389,7 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
// connection. If a raw cert was specified in the config, then
// we'll set that directly. Otherwise, we attempt to read the
// cert from the path specified in the config.
var btcdMode *btcdConfig
var btcdMode *lncfg.Btcd
switch {
case cfg.Bitcoin.Active:
btcdMode = cfg.BtcdMode
@ -504,7 +505,7 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
// Select the default channel constraints for the primary chain.
channelConstraints := defaultBtcChannelConstraints
if registeredChains.PrimaryChain() == litecoinChain {
if cfg.registeredChains.PrimaryChain() == litecoinChain {
channelConstraints = defaultLtcChannelConstraints
}
@ -718,7 +719,9 @@ func (c *chainRegistry) NumActiveChains() uint32 {
// initNeutrinoBackend inits a new instance of the neutrino light client
// backend given a target chain directory to store the chain state.
func initNeutrinoBackend(chainDir string) (*neutrino.ChainService, func(), error) {
func initNeutrinoBackend(cfg *Config, chainDir string) (*neutrino.ChainService,
func(), error) {
// First we'll open the database file for neutrino, creating the
// database if needed. We append the normalized network name here to
// match the behavior of btcwallet.

View File

@ -4,17 +4,32 @@ import (
"fmt"
"os"
flags "github.com/jessevdk/go-flags"
"github.com/jessevdk/go-flags"
"github.com/lightningnetwork/lnd"
"github.com/lightningnetwork/lnd/signal"
)
func main() {
// Load the configuration, and parse any command line options. This
// function will also set up logging properly.
loadedConfig, err := lnd.LoadConfig()
if err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
// Hook interceptor for os signals.
signal.Intercept()
// Call the "real" main in a nested manner so the defers will properly
// be executed in the case of a graceful shutdown.
if err := lnd.Main(lnd.ListenerCfg{}); err != nil {
err = lnd.Main(
loadedConfig, lnd.ListenerCfg{}, signal.ShutdownChannel(),
)
if err != nil {
if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
} else {
fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, err)
}
os.Exit(1)
}

387
config.go
View File

@ -1,6 +1,6 @@
// Copyright (c) 2013-2017 The btcsuite developers
// Copyright (c) 2015-2016 The Decred developers
// Copyright (C) 2015-2017 The Lightning Network Developers
// Copyright (C) 2015-2020 The Lightning Network Developers
package lnd
@ -30,13 +30,11 @@ import (
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lnrpc/signrpc"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing"
"github.com/lightningnetwork/lnd/tor"
)
const (
defaultConfigFilename = "lnd.conf"
defaultDataDirname = "data"
defaultChainSubDirname = "chain"
defaultGraphSubDirname = "graph"
@ -54,10 +52,6 @@ const (
defaultPeerPort = 9735
defaultRPCHost = "localhost"
// DefaultMaxPendingChannels is the default maximum number of incoming
// pending channels permitted per peer.
DefaultMaxPendingChannels = 1
defaultNoSeedBackup = false
defaultPaymentsExpirationGracePeriod = time.Duration(0)
defaultTrickleDelay = 90 * 1000
@ -76,51 +70,6 @@ const (
defaultTorV2PrivateKeyFilename = "v2_onion_private_key"
defaultTorV3PrivateKeyFilename = "v3_onion_private_key"
// DefaultIncomingBroadcastDelta defines the number of blocks before the
// expiry of an incoming htlc at which we force close the channel. We
// only go to chain if we also have the preimage to actually pull in the
// htlc. BOLT #2 suggests 7 blocks. We use a few more for extra safety.
// Within this window we need to get our sweep or 2nd level success tx
// confirmed, because after that the remote party is also able to claim
// the htlc using the timeout path.
DefaultIncomingBroadcastDelta = 10
// defaultFinalCltvRejectDelta defines the number of blocks before the
// expiry of an incoming exit hop htlc at which we cancel it back
// immediately. It is an extra safety measure over the final cltv
// requirement as it is defined in the invoice. It ensures that we
// cancel back htlcs that, when held on to, may cause us to force close
// the channel because we enter the incoming broadcast window. Bolt #11
// suggests 9 blocks here. We use a few more for additional safety.
//
// There is still a small gap that remains between receiving the
// RevokeAndAck and canceling back. If a new block arrives within that
// window, we may still force close the channel. There is currently no
// way to reject an UpdateAddHtlc of which we already know that it will
// push us in the broadcast window.
defaultFinalCltvRejectDelta = DefaultIncomingBroadcastDelta + 3
// DefaultOutgoingBroadcastDelta defines the number of blocks before the
// expiry of an outgoing htlc at which we force close the channel. We
// are not in a hurry to force close, because there is nothing to claim
// for us. We do need to time the htlc out, because there may be an
// incoming htlc that will time out too (albeit later). Bolt #2 suggests
// a value of -1 here, but we allow one block less to prevent potential
// confusion around the negative value. It means we force close the
// channel at exactly the htlc expiry height.
DefaultOutgoingBroadcastDelta = 0
// defaultOutgoingCltvRejectDelta defines the number of blocks before
// the expiry of an outgoing htlc at which we don't want to offer it to
// the next peer anymore. If that happens, we cancel back the incoming
// htlc. This is to prevent the situation where we have an outstanding
// htlc that brings or will soon bring us inside the outgoing broadcast
// window and trigger us to force close the channel. Bolt #2 suggests a
// value of 0. We pad it a bit, to prevent a slow round trip to the next
// peer and a block arriving during that round trip to trigger force
// closure.
defaultOutgoingCltvRejectDelta = DefaultOutgoingBroadcastDelta + 3
// minTimeLockDelta is the minimum timelock we require for incoming
// HTLCs on our channels.
minTimeLockDelta = 4
@ -134,15 +83,25 @@ const (
)
var (
defaultLndDir = btcutil.AppDataDir("lnd", false)
defaultConfigFile = filepath.Join(defaultLndDir, defaultConfigFilename)
defaultDataDir = filepath.Join(defaultLndDir, defaultDataDirname)
defaultLogDir = filepath.Join(defaultLndDir, defaultLogDirname)
// DefaultLndDir is the default directory where lnd tries to find its
// configuration file and store its data. This is a directory in the
// user's application data, for example:
// C:\Users\<username>\AppData\Local\Lnd on Windows
// ~/.lnd on Linux
// ~/Library/Application Support/Lnd on MacOS
DefaultLndDir = btcutil.AppDataDir("lnd", false)
// DefaultConfigFile is the default full path of lnd's configuration
// file.
DefaultConfigFile = filepath.Join(DefaultLndDir, lncfg.DefaultConfigFilename)
defaultDataDir = filepath.Join(DefaultLndDir, defaultDataDirname)
defaultLogDir = filepath.Join(DefaultLndDir, defaultLogDirname)
defaultTowerDir = filepath.Join(defaultDataDir, defaultTowerSubDirname)
defaultTLSCertPath = filepath.Join(defaultLndDir, defaultTLSCertFilename)
defaultTLSKeyPath = filepath.Join(defaultLndDir, defaultTLSKeyFilename)
defaultTLSCertPath = filepath.Join(DefaultLndDir, defaultTLSCertFilename)
defaultTLSKeyPath = filepath.Join(DefaultLndDir, defaultTLSKeyFilename)
defaultBtcdDir = btcutil.AppDataDir("btcd", false)
defaultBtcdRPCCertFile = filepath.Join(defaultBtcdDir, "rpc.cert")
@ -163,86 +122,11 @@ var (
bitcoindEstimateModes = [2]string{"ECONOMICAL", defaultBitcoindEstimateMode}
)
type chainConfig struct {
Active bool `long:"active" description:"If the chain should be active or not."`
ChainDir string `long:"chaindir" description:"The directory to store the chain's data within."`
Node string `long:"node" description:"The blockchain interface to use." choice:"btcd" choice:"bitcoind" choice:"neutrino" choice:"ltcd" choice:"litecoind"`
MainNet bool `long:"mainnet" description:"Use the main network"`
TestNet3 bool `long:"testnet" description:"Use the test network"`
SimNet bool `long:"simnet" description:"Use the simulation test network"`
RegTest bool `long:"regtest" description:"Use the regression test network"`
DefaultNumChanConfs int `long:"defaultchanconfs" description:"The default number of confirmations a channel must have before it's considered open. If this is not set, we will scale the value according to the channel size."`
DefaultRemoteDelay int `long:"defaultremotedelay" description:"The default number of blocks we will require our channel counterparty to wait before accessing its funds in case of unilateral close. If this is not set, we will scale the value according to the channel size."`
MinHTLCIn lnwire.MilliSatoshi `long:"minhtlc" description:"The smallest HTLC we are willing to accept on our channels, in millisatoshi"`
MinHTLCOut lnwire.MilliSatoshi `long:"minhtlcout" description:"The smallest HTLC we are willing to send out on our channels, in millisatoshi"`
BaseFee lnwire.MilliSatoshi `long:"basefee" description:"The base fee in millisatoshi we will charge for forwarding payments on our channels"`
FeeRate lnwire.MilliSatoshi `long:"feerate" description:"The fee rate used when forwarding payments on our channels. The total fee charged is basefee + (amount * feerate / 1000000), where amount is the forwarded amount."`
TimeLockDelta uint32 `long:"timelockdelta" description:"The CLTV delta we will subtract from a forwarded HTLC's timelock value"`
}
type neutrinoConfig struct {
AddPeers []string `short:"a" long:"addpeer" description:"Add a peer to connect with at startup"`
ConnectPeers []string `long:"connect" description:"Connect only to the specified peers at startup"`
MaxPeers int `long:"maxpeers" description:"Max number of inbound and outbound peers"`
BanDuration time.Duration `long:"banduration" description:"How long to ban misbehaving peers. Valid time units are {s, m, h}. Minimum 1 second"`
BanThreshold uint32 `long:"banthreshold" description:"Maximum allowed ban score before disconnecting and banning misbehaving peers."`
FeeURL string `long:"feeurl" description:"Optional URL for fee estimation. If a URL is not specified, static fees will be used for estimation."`
AssertFilterHeader string `long:"assertfilterheader" description:"Optional filter header in height:hash format to assert the state of neutrino's filter header chain on startup. If the assertion does not hold, then the filter header chain will be re-synced from the genesis block."`
}
type btcdConfig struct {
Dir string `long:"dir" description:"The base directory that contains the node's data, logs, configuration file, etc."`
RPCHost string `long:"rpchost" description:"The daemon's rpc listening address. If a port is omitted, then the default port for the selected chain parameters will be used."`
RPCUser string `long:"rpcuser" description:"Username for RPC connections"`
RPCPass string `long:"rpcpass" default-mask:"-" description:"Password for RPC connections"`
RPCCert string `long:"rpccert" description:"File containing the daemon's certificate file"`
RawRPCCert string `long:"rawrpccert" description:"The raw bytes of the daemon's PEM-encoded certificate chain which will be used to authenticate the RPC connection."`
}
type bitcoindConfig struct {
Dir string `long:"dir" description:"The base directory that contains the node's data, logs, configuration file, etc."`
RPCHost string `long:"rpchost" description:"The daemon's rpc listening address. If a port is omitted, then the default port for the selected chain parameters will be used."`
RPCUser string `long:"rpcuser" description:"Username for RPC connections"`
RPCPass string `long:"rpcpass" default-mask:"-" description:"Password for RPC connections"`
ZMQPubRawBlock string `long:"zmqpubrawblock" description:"The address listening for ZMQ connections to deliver raw block notifications"`
ZMQPubRawTx string `long:"zmqpubrawtx" description:"The address listening for ZMQ connections to deliver raw transaction notifications"`
EstimateMode string `long:"estimatemode" description:"The fee estimate mode. Must be either ECONOMICAL or CONSERVATIVE."`
}
type autoPilotConfig struct {
Active bool `long:"active" description:"If the autopilot agent should be active or not."`
Heuristic map[string]float64 `long:"heuristic" description:"Heuristic to activate, and the weight to give it during scoring."`
MaxChannels int `long:"maxchannels" description:"The maximum number of channels that should be created"`
Allocation float64 `long:"allocation" description:"The percentage of total funds that should be committed to automatic channel establishment"`
MinChannelSize int64 `long:"minchansize" description:"The smallest channel that the autopilot agent should create"`
MaxChannelSize int64 `long:"maxchansize" description:"The largest channel that the autopilot agent should create"`
Private bool `long:"private" description:"Whether the channels created by the autopilot agent should be private or not. Private channels won't be announced to the network."`
MinConfs int32 `long:"minconfs" description:"The minimum number of confirmations each of your inputs in funding transactions created by the autopilot agent must have."`
ConfTarget uint32 `long:"conftarget" description:"The confirmation target (in blocks) for channels opened by autopilot."`
}
type torConfig struct {
Active bool `long:"active" description:"Allow outbound and inbound connections to be routed through Tor"`
SOCKS string `long:"socks" description:"The host:port that Tor's exposed SOCKS5 proxy is listening on"`
DNS string `long:"dns" description:"The DNS server as host:port that Tor will use for SRV queries - NOTE must have TCP resolution enabled"`
StreamIsolation bool `long:"streamisolation" description:"Enable Tor stream isolation by randomizing user credentials for each connection."`
Control string `long:"control" description:"The host:port that Tor is listening on for Tor control connections"`
TargetIPAddress string `long:"targetipaddress" description:"IP address that Tor should use as the target of the hidden service"`
Password string `long:"password" description:"The password used to arrive at the HashedControlPassword for the control port. If provided, the HASHEDPASSWORD authentication method will be used instead of the SAFECOOKIE one."`
V2 bool `long:"v2" description:"Automatically set up a v2 onion service to listen for inbound connections"`
V3 bool `long:"v3" description:"Automatically set up a v3 onion service to listen for inbound connections"`
PrivateKeyPath string `long:"privatekeypath" description:"The path to the private key of the onion service being created"`
WatchtowerKeyPath string `long:"watchtowerkeypath" description:"The path to the private key of the watchtower onion service being created"`
}
// config defines the configuration options for lnd.
// Config defines the configuration options for lnd.
//
// See loadConfig for further details regarding the configuration
// See LoadConfig for further details regarding the configuration
// loading+parsing process.
type config struct {
type Config struct {
ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"`
LndDir string `long:"lnddir" description:"The base directory that contains lnd's data, logs, configuration file, etc."`
@ -294,18 +178,18 @@ type config struct {
MaxPendingChannels int `long:"maxpendingchannels" description:"The maximum number of incoming pending channels permitted per peer."`
BackupFilePath string `long:"backupfilepath" description:"The target location of the channel backup file"`
Bitcoin *chainConfig `group:"Bitcoin" namespace:"bitcoin"`
BtcdMode *btcdConfig `group:"btcd" namespace:"btcd"`
BitcoindMode *bitcoindConfig `group:"bitcoind" namespace:"bitcoind"`
NeutrinoMode *neutrinoConfig `group:"neutrino" namespace:"neutrino"`
Bitcoin *lncfg.Chain `group:"Bitcoin" namespace:"bitcoin"`
BtcdMode *lncfg.Btcd `group:"btcd" namespace:"btcd"`
BitcoindMode *lncfg.Bitcoind `group:"bitcoind" namespace:"bitcoind"`
NeutrinoMode *lncfg.Neutrino `group:"neutrino" namespace:"neutrino"`
Litecoin *chainConfig `group:"Litecoin" namespace:"litecoin"`
LtcdMode *btcdConfig `group:"ltcd" namespace:"ltcd"`
LitecoindMode *bitcoindConfig `group:"litecoind" namespace:"litecoind"`
Litecoin *lncfg.Chain `group:"Litecoin" namespace:"litecoin"`
LtcdMode *lncfg.Btcd `group:"ltcd" namespace:"ltcd"`
LitecoindMode *lncfg.Bitcoind `group:"litecoind" namespace:"litecoind"`
Autopilot *autoPilotConfig `group:"Autopilot" namespace:"autopilot"`
Autopilot *lncfg.AutoPilot `group:"Autopilot" namespace:"autopilot"`
Tor *torConfig `group:"Tor" namespace:"tor"`
Tor *lncfg.Tor `group:"Tor" namespace:"tor"`
SubRPCServers *subRPCServerConfigs `group:"subrpc"`
@ -363,20 +247,22 @@ type config struct {
ProtocolOptions *lncfg.ProtocolOptions `group:"protocol" namespace:"protocol"`
AllowCircularRoute bool `long:"allow-circular-route" description:"If true, our node will allow htlc forwards that arrive and depart on the same channel."`
// registeredChains keeps track of all chains that have been registered
// with the daemon.
registeredChains *chainRegistry
// networkDir is the path to the directory of the currently active
// network. This path will hold the files related to each different
// network.
networkDir string
}
// loadConfig initializes and parses the config using a config file and command
// line options.
//
// The configuration proceeds as follows:
// 1) Start with a default config with sane settings
// 2) Pre-parse the command line to check for an alternative config file
// 3) Load configuration file overwriting defaults with any specified options
// 4) Parse CLI options and overwrite/add any specified options
func loadConfig() (*config, error) {
defaultCfg := config{
LndDir: defaultLndDir,
ConfigFile: defaultConfigFile,
// DefaultConfig returns all default values for the Config struct.
func DefaultConfig() Config {
return Config{
LndDir: DefaultLndDir,
ConfigFile: DefaultConfigFile,
DataDir: defaultDataDir,
DebugLevel: defaultLogLevel,
TLSCertPath: defaultTLSCertPath,
@ -385,7 +271,7 @@ func loadConfig() (*config, error) {
MaxLogFiles: defaultMaxLogFiles,
MaxLogFileSize: defaultMaxLogFileSize,
AcceptorTimeout: defaultAcceptorTimeout,
Bitcoin: &chainConfig{
Bitcoin: &lncfg.Chain{
MinHTLCIn: defaultBitcoinMinHTLCInMSat,
MinHTLCOut: defaultBitcoinMinHTLCOutMSat,
BaseFee: DefaultBitcoinBaseFeeMSat,
@ -393,17 +279,17 @@ func loadConfig() (*config, error) {
TimeLockDelta: DefaultBitcoinTimeLockDelta,
Node: "btcd",
},
BtcdMode: &btcdConfig{
BtcdMode: &lncfg.Btcd{
Dir: defaultBtcdDir,
RPCHost: defaultRPCHost,
RPCCert: defaultBtcdRPCCertFile,
},
BitcoindMode: &bitcoindConfig{
BitcoindMode: &lncfg.Bitcoind{
Dir: defaultBitcoindDir,
RPCHost: defaultRPCHost,
EstimateMode: defaultBitcoindEstimateMode,
},
Litecoin: &chainConfig{
Litecoin: &lncfg.Chain{
MinHTLCIn: defaultLitecoinMinHTLCInMSat,
MinHTLCOut: defaultLitecoinMinHTLCOutMSat,
BaseFee: defaultLitecoinBaseFeeMSat,
@ -411,18 +297,18 @@ func loadConfig() (*config, error) {
TimeLockDelta: defaultLitecoinTimeLockDelta,
Node: "ltcd",
},
LtcdMode: &btcdConfig{
LtcdMode: &lncfg.Btcd{
Dir: defaultLtcdDir,
RPCHost: defaultRPCHost,
RPCCert: defaultLtcdRPCCertFile,
},
LitecoindMode: &bitcoindConfig{
LitecoindMode: &lncfg.Bitcoind{
Dir: defaultLitecoindDir,
RPCHost: defaultRPCHost,
EstimateMode: defaultBitcoindEstimateMode,
},
UnsafeDisconnect: true,
MaxPendingChannels: DefaultMaxPendingChannels,
MaxPendingChannels: lncfg.DefaultMaxPendingChannels,
NoSeedBackup: defaultNoSeedBackup,
MinBackoff: defaultMinBackoff,
MaxBackoff: defaultMaxBackoff,
@ -430,7 +316,7 @@ func loadConfig() (*config, error) {
SignRPC: &signrpc.Config{},
RouterRPC: routerrpc.DefaultConfig(),
},
Autopilot: &autoPilotConfig{
Autopilot: &lncfg.AutoPilot{
MaxChannels: 5,
Allocation: 0.6,
MinChannelSize: int64(minChanFundingSize),
@ -451,7 +337,7 @@ func loadConfig() (*config, error) {
MinChanSize: int64(minChanFundingSize),
NumGraphSyncPeers: defaultMinPeers,
HistoricalSyncInterval: discovery.DefaultHistoricalSyncInterval,
Tor: &torConfig{
Tor: &lncfg.Tor{
SOCKS: defaultTorSOCKS,
DNS: defaultTorDNS,
Control: defaultTorControl,
@ -472,11 +358,22 @@ func loadConfig() (*config, error) {
},
MaxOutgoingCltvExpiry: htlcswitch.DefaultMaxOutgoingCltvExpiry,
MaxChannelFeeAllocation: htlcswitch.DefaultMaxLinkFeeAllocation,
registeredChains: newChainRegistry(),
}
}
// LoadConfig initializes and parses the config using a config file and command
// line options.
//
// The configuration proceeds as follows:
// 1) Start with a default config with sane settings
// 2) Pre-parse the command line to check for an alternative config file
// 3) Load configuration file overwriting defaults with any specified options
// 4) Parse CLI options and overwrite/add any specified options
func LoadConfig() (*Config, error) {
// Pre-parse the command line options to pick up an alternative config
// file.
preCfg := defaultCfg
preCfg := DefaultConfig()
if _, err := flags.Parse(&preCfg); err != nil {
return nil, err
}
@ -495,12 +392,12 @@ func loadConfig() (*config, error) {
// use the default config file path. However, if the user has modified
// their lnddir, then we should assume they intend to use the config
// file within it.
configFileDir := cleanAndExpandPath(preCfg.LndDir)
configFilePath := cleanAndExpandPath(preCfg.ConfigFile)
if configFileDir != defaultLndDir {
if configFilePath == defaultConfigFile {
configFileDir := CleanAndExpandPath(preCfg.LndDir)
configFilePath := CleanAndExpandPath(preCfg.ConfigFile)
if configFileDir != DefaultLndDir {
if configFilePath == DefaultConfigFile {
configFilePath = filepath.Join(
configFileDir, defaultConfigFilename,
configFileDir, lncfg.DefaultConfigFilename,
)
}
}
@ -525,10 +422,30 @@ func loadConfig() (*config, error) {
return nil, err
}
// Make sure everything we just loaded makes sense.
cleanCfg, err := ValidateConfig(cfg, usageMessage)
if err != nil {
return nil, err
}
// Warn about missing config file only after all other configuration is
// done. This prevents the warning on help messages and invalid
// options. Note this should go directly before the return.
if configFileError != nil {
ltndLog.Warnf("%v", configFileError)
}
return cleanCfg, nil
}
// 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
// normalized. The cleaned up config is returned on success.
func ValidateConfig(cfg Config, usageMessage string) (*Config, error) {
// 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.
lndDir := cleanAndExpandPath(cfg.LndDir)
if lndDir != defaultLndDir {
lndDir := CleanAndExpandPath(cfg.LndDir)
if lndDir != DefaultLndDir {
cfg.DataDir = filepath.Join(lndDir, defaultDataDirname)
cfg.TLSCertPath = filepath.Join(lndDir, defaultTLSCertFilename)
cfg.TLSKeyPath = filepath.Join(lndDir, defaultTLSKeyFilename)
@ -558,64 +475,64 @@ func loadConfig() (*config, error) {
str := "%s: Failed to create lnd directory: %v"
err := fmt.Errorf(str, funcName, err)
fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
}
// As soon as we're done parsing configuration options, ensure all paths
// to directories and files are cleaned and expanded before attempting
// to use them later on.
cfg.DataDir = cleanAndExpandPath(cfg.DataDir)
cfg.TLSCertPath = cleanAndExpandPath(cfg.TLSCertPath)
cfg.TLSKeyPath = cleanAndExpandPath(cfg.TLSKeyPath)
cfg.AdminMacPath = cleanAndExpandPath(cfg.AdminMacPath)
cfg.ReadMacPath = cleanAndExpandPath(cfg.ReadMacPath)
cfg.InvoiceMacPath = cleanAndExpandPath(cfg.InvoiceMacPath)
cfg.LogDir = cleanAndExpandPath(cfg.LogDir)
cfg.BtcdMode.Dir = cleanAndExpandPath(cfg.BtcdMode.Dir)
cfg.LtcdMode.Dir = cleanAndExpandPath(cfg.LtcdMode.Dir)
cfg.BitcoindMode.Dir = cleanAndExpandPath(cfg.BitcoindMode.Dir)
cfg.LitecoindMode.Dir = cleanAndExpandPath(cfg.LitecoindMode.Dir)
cfg.Tor.PrivateKeyPath = cleanAndExpandPath(cfg.Tor.PrivateKeyPath)
cfg.Tor.WatchtowerKeyPath = cleanAndExpandPath(cfg.Tor.WatchtowerKeyPath)
cfg.Watchtower.TowerDir = cleanAndExpandPath(cfg.Watchtower.TowerDir)
cfg.DataDir = CleanAndExpandPath(cfg.DataDir)
cfg.TLSCertPath = CleanAndExpandPath(cfg.TLSCertPath)
cfg.TLSKeyPath = CleanAndExpandPath(cfg.TLSKeyPath)
cfg.AdminMacPath = CleanAndExpandPath(cfg.AdminMacPath)
cfg.ReadMacPath = CleanAndExpandPath(cfg.ReadMacPath)
cfg.InvoiceMacPath = CleanAndExpandPath(cfg.InvoiceMacPath)
cfg.LogDir = CleanAndExpandPath(cfg.LogDir)
cfg.BtcdMode.Dir = CleanAndExpandPath(cfg.BtcdMode.Dir)
cfg.LtcdMode.Dir = CleanAndExpandPath(cfg.LtcdMode.Dir)
cfg.BitcoindMode.Dir = CleanAndExpandPath(cfg.BitcoindMode.Dir)
cfg.LitecoindMode.Dir = CleanAndExpandPath(cfg.LitecoindMode.Dir)
cfg.Tor.PrivateKeyPath = CleanAndExpandPath(cfg.Tor.PrivateKeyPath)
cfg.Tor.WatchtowerKeyPath = CleanAndExpandPath(cfg.Tor.WatchtowerKeyPath)
cfg.Watchtower.TowerDir = CleanAndExpandPath(cfg.Watchtower.TowerDir)
// Ensure that the user didn't attempt to specify negative values for
// any of the autopilot params.
if cfg.Autopilot.MaxChannels < 0 {
str := "%s: autopilot.maxchannels must be non-negative"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
}
if cfg.Autopilot.Allocation < 0 {
str := "%s: autopilot.allocation must be non-negative"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
}
if cfg.Autopilot.MinChannelSize < 0 {
str := "%s: autopilot.minchansize must be non-negative"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
}
if cfg.Autopilot.MaxChannelSize < 0 {
str := "%s: autopilot.maxchansize must be non-negative"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
}
if cfg.Autopilot.MinConfs < 0 {
str := "%s: autopilot.minconfs must be non-negative"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
}
if cfg.Autopilot.ConfTarget < 1 {
str := "%s: autopilot.conftarget must be positive"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
}
@ -829,7 +746,7 @@ func loadConfig() (*config, error) {
// Finally we'll register the litecoin chain as our current
// primary chain.
registeredChains.RegisterPrimaryChain(litecoinChain)
cfg.registeredChains.RegisterPrimaryChain(litecoinChain)
MaxFundingAmount = maxLtcFundingAmount
MaxPaymentMSat = maxLtcPaymentMSat
@ -916,7 +833,7 @@ func loadConfig() (*config, error) {
// Finally we'll register the bitcoin chain as our current
// primary chain.
registeredChains.RegisterPrimaryChain(bitcoinChain)
cfg.registeredChains.RegisterPrimaryChain(bitcoinChain)
}
// Ensure that the user didn't attempt to specify negative values for
@ -924,25 +841,25 @@ func loadConfig() (*config, error) {
if cfg.Autopilot.MaxChannels < 0 {
str := "%s: autopilot.maxchannels must be non-negative"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
}
if cfg.Autopilot.Allocation < 0 {
str := "%s: autopilot.allocation must be non-negative"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
}
if cfg.Autopilot.MinChannelSize < 0 {
str := "%s: autopilot.minchansize must be non-negative"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
}
if cfg.Autopilot.MaxChannelSize < 0 {
str := "%s: autopilot.maxchansize must be non-negative"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
}
@ -961,17 +878,17 @@ func loadConfig() (*config, error) {
if err != nil || profilePort < 1024 || profilePort > 65535 {
str := "%s: The profile port must be between 1024 and 65535"
err := fmt.Errorf(str, funcName)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
_, _ = fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, usageMessage)
return nil, err
}
}
// We'll now construct the network directory which will be where we
// store all the data specific to this chain/network.
networkDir = filepath.Join(
cfg.networkDir = filepath.Join(
cfg.DataDir, defaultChainSubDirname,
registeredChains.PrimaryChain().String(),
cfg.registeredChains.PrimaryChain().String(),
normalizeNetwork(activeNetParams.Name),
)
@ -980,17 +897,17 @@ func loadConfig() (*config, error) {
// the path for the macaroons to be generated.
if cfg.AdminMacPath == "" {
cfg.AdminMacPath = filepath.Join(
networkDir, defaultAdminMacFilename,
cfg.networkDir, defaultAdminMacFilename,
)
}
if cfg.ReadMacPath == "" {
cfg.ReadMacPath = filepath.Join(
networkDir, defaultReadMacFilename,
cfg.networkDir, defaultReadMacFilename,
)
}
if cfg.InvoiceMacPath == "" {
cfg.InvoiceMacPath = filepath.Join(
networkDir, defaultInvoiceMacFilename,
cfg.networkDir, defaultInvoiceMacFilename,
)
}
@ -998,41 +915,41 @@ func loadConfig() (*config, error) {
// we'll update the file location to match our set network directory.
if cfg.BackupFilePath == "" {
cfg.BackupFilePath = filepath.Join(
networkDir, chanbackup.DefaultBackupFileName,
cfg.networkDir, chanbackup.DefaultBackupFileName,
)
}
// Append the network type to the log directory so it is "namespaced"
// per network in the same fashion as the data directory.
cfg.LogDir = filepath.Join(cfg.LogDir,
registeredChains.PrimaryChain().String(),
cfg.registeredChains.PrimaryChain().String(),
normalizeNetwork(activeNetParams.Name))
// Special show command to list supported subsystems and exit.
if cfg.DebugLevel == "show" {
fmt.Println("Supported subsystems",
logWriter.SupportedSubsystems())
RootLogWriter.SupportedSubsystems())
os.Exit(0)
}
// Initialize logging at the default logging level.
err = logWriter.InitLogRotator(
err = RootLogWriter.InitLogRotator(
filepath.Join(cfg.LogDir, defaultLogFilename),
cfg.MaxLogFileSize, cfg.MaxLogFiles,
)
if err != nil {
str := "%s: log rotation setup failed: %v"
err = fmt.Errorf(str, funcName, err.Error())
fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, err)
return nil, err
}
// Parse, validate, and set debug log level(s).
err = build.ParseAndSetDebugLevels(cfg.DebugLevel, logWriter)
err = build.ParseAndSetDebugLevels(cfg.DebugLevel, RootLogWriter)
if err != nil {
err = fmt.Errorf("%s: %v", funcName, err.Error())
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
_, _ = fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, usageMessage)
return nil, err
}
@ -1169,20 +1086,14 @@ func loadConfig() (*config, error) {
return nil, fmt.Errorf("unable to parse node color: %v", err)
}
// Warn about missing config file only after all other configuration is
// done. This prevents the warning on help messages and invalid
// options. Note this should go directly before the return.
if configFileError != nil {
ltndLog.Warnf("%v", configFileError)
}
return &cfg, nil
// All good, return the sanitized result.
return &cfg, err
}
// cleanAndExpandPath expands environment variables and leading ~ in the
// CleanAndExpandPath expands environment variables and leading ~ in the
// passed path, cleans the result, and returns it.
// This function is taken from https://github.com/btcsuite/btcd
func cleanAndExpandPath(path string) string {
func CleanAndExpandPath(path string) string {
if path == "" {
return ""
}
@ -1190,9 +1101,9 @@ func cleanAndExpandPath(path string) string {
// Expand initial ~ to OS specific home directory.
if strings.HasPrefix(path, "~") {
var homeDir string
user, err := user.Current()
u, err := user.Current()
if err == nil {
homeDir = user.HomeDir
homeDir = u.HomeDir
} else {
homeDir = os.Getenv("HOME")
}
@ -1205,15 +1116,15 @@ func cleanAndExpandPath(path string) string {
return filepath.Clean(os.ExpandEnv(path))
}
func parseRPCParams(cConfig *chainConfig, nodeConfig interface{}, net chainCode,
funcName string) error {
func parseRPCParams(cConfig *lncfg.Chain, nodeConfig interface{}, net chainCode,
funcName string) error { // nolint:unparam
// 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
// depending on the backend node.
var daemonName, confDir, confFile string
switch conf := nodeConfig.(type) {
case *btcdConfig:
case *lncfg.Btcd:
// If both RPCUser and RPCPass are set, we assume those
// credentials are good to use.
if conf.RPCUser != "" && conf.RPCPass != "" {
@ -1239,7 +1150,7 @@ func parseRPCParams(cConfig *chainConfig, nodeConfig interface{}, net chainCode,
"%[1]v.rpcuser, %[1]v.rpcpass", daemonName)
}
case *bitcoindConfig:
case *lncfg.Bitcoind:
// Ensure that if the ZMQ options are set, that they are not
// equal.
if conf.ZMQPubRawBlock != "" && conf.ZMQPubRawTx != "" {
@ -1305,7 +1216,7 @@ func parseRPCParams(cConfig *chainConfig, nodeConfig interface{}, net chainCode,
confFile = filepath.Join(confDir, fmt.Sprintf("%v.conf", confFile))
switch cConfig.Node {
case "btcd", "ltcd":
nConf := nodeConfig.(*btcdConfig)
nConf := nodeConfig.(*lncfg.Btcd)
rpcUser, rpcPass, err := extractBtcdRPCParams(confFile)
if err != nil {
return fmt.Errorf("unable to extract RPC credentials:"+
@ -1314,7 +1225,7 @@ func parseRPCParams(cConfig *chainConfig, nodeConfig interface{}, net chainCode,
}
nConf.RPCUser, nConf.RPCPass = rpcUser, rpcPass
case "bitcoind", "litecoind":
nConf := nodeConfig.(*bitcoindConfig)
nConf := nodeConfig.(*lncfg.Bitcoind)
rpcUser, rpcPass, zmqBlockHost, zmqTxHost, err :=
extractBitcoindRPCParams(confFile)
if err != nil {
@ -1340,7 +1251,7 @@ func extractBtcdRPCParams(btcdConfigPath string) (string, string, error) {
if err != nil {
return "", "", err
}
defer btcdConfigFile.Close()
defer func() { _ = btcdConfigFile.Close() }()
// With the file open extract the contents of the configuration file so
// we can attempt to locate the RPC credentials.
@ -1381,14 +1292,16 @@ func extractBtcdRPCParams(btcdConfigPath string) (string, string, error) {
// location of bitcoind's bitcoin.conf on the target system. The routine looks
// for a cookie first, optionally following the datadir configuration option in
// the bitcoin.conf. If it doesn't find one, it looks for rpcuser/rpcpassword.
func extractBitcoindRPCParams(bitcoindConfigPath string) (string, string, string, string, error) {
func extractBitcoindRPCParams(bitcoindConfigPath string) (string, string, string,
string, error) {
// First, we'll open up the bitcoind configuration file found at the
// target destination.
bitcoindConfigFile, err := os.Open(bitcoindConfigPath)
if err != nil {
return "", "", "", "", err
}
defer bitcoindConfigFile.Close()
defer func() { _ = bitcoindConfigFile.Close() }()
// With the file open extract the contents of the configuration file so
// we can attempt to locate the RPC credentials.

View File

@ -369,6 +369,14 @@ type fundingConfig struct {
// NotifyPendingOpenChannelEvent informs the ChannelNotifier when channels
// enter a pending state.
NotifyPendingOpenChannelEvent func(wire.OutPoint, *channeldb.OpenChannel)
// EnableUpfrontShutdown specifies whether the upfront shutdown script
// is enabled.
EnableUpfrontShutdown bool
// RegisteredChains keeps track of all chains that have been registered
// with the daemon.
RegisteredChains *chainRegistry
}
// fundingManager acts as an orchestrator/bridge between the wallet's
@ -1322,7 +1330,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
// A nil address is set in place of user input, because this channel open
// was not initiated by the user.
shutdown, err := getUpfrontShutdownScript(
fmsg.peer, nil,
f.cfg.EnableUpfrontShutdown, fmsg.peer, nil,
func() (lnwire.DeliveryAddress, error) {
addr, err := f.cfg.Wallet.NewAddress(lnwallet.WitnessPubKey, false)
if err != nil {
@ -2981,7 +2989,8 @@ func (f *fundingManager) initFundingWorkflow(peer lnpeer.Peer, req *openChanReq)
// our peer does support the feature, we will return the user provided script
// if non-zero, or a freshly generated script if our node is configured to set
// upfront shutdown scripts automatically.
func getUpfrontShutdownScript(peer lnpeer.Peer, script lnwire.DeliveryAddress,
func getUpfrontShutdownScript(enableUpfrontShutdown bool, peer lnpeer.Peer,
script lnwire.DeliveryAddress,
getScript func() (lnwire.DeliveryAddress, error)) (lnwire.DeliveryAddress,
error) {
@ -3010,7 +3019,7 @@ func getUpfrontShutdownScript(peer lnpeer.Peer, script lnwire.DeliveryAddress,
// If we do not have setting of upfront shutdown script enabled, return
// an empty script.
if !cfg.EnableUpfrontShutdown {
if !enableUpfrontShutdown {
return nil, nil
}
@ -3030,7 +3039,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
// We'll determine our dust limit depending on which chain is active.
var ourDustLimit btcutil.Amount
switch registeredChains.PrimaryChain() {
switch f.cfg.RegisteredChains.PrimaryChain() {
case bitcoinChain:
ourDustLimit = lnwallet.DefaultDustLimit()
case litecoinChain:
@ -3084,7 +3093,8 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
// address from the wallet if our node is configured to set shutdown
// address by default).
shutdown, err := getUpfrontShutdownScript(
msg.peer, msg.openChanReq.shutdownScript,
f.cfg.EnableUpfrontShutdown, msg.peer,
msg.openChanReq.shutdownScript,
func() (lnwire.DeliveryAddress, error) {
addr, err := f.cfg.Wallet.NewAddress(
lnwallet.WitnessPubKey, false,

View File

@ -21,6 +21,7 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/chanacceptor"
@ -417,10 +418,11 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
},
ZombieSweeperInterval: 1 * time.Hour,
ReservationTimeout: 1 * time.Nanosecond,
MaxPendingChannels: DefaultMaxPendingChannels,
MaxPendingChannels: lncfg.DefaultMaxPendingChannels,
NotifyOpenChannelEvent: evt.NotifyOpenChannelEvent,
OpenChannelPredicate: chainedAcceptor,
NotifyPendingOpenChannelEvent: evt.NotifyPendingOpenChannelEvent,
RegisteredChains: newChainRegistry(),
}
for _, op := range options {
@ -3087,11 +3089,9 @@ func TestGetUpfrontShutdownScript(t *testing.T) {
}
}
// Set the command line option in config as needed.
cfg = &config{EnableUpfrontShutdown: test.localEnabled}
addr, err := getUpfrontShutdownScript(
&mockPeer, test.upfrontScript, test.getScript,
test.localEnabled, &mockPeer, test.upfrontScript,
test.getScript,
)
if err != test.expectedErr {
t.Fatalf("got: %v, expected error: %v", err, test.expectedErr)

14
lncfg/autopilot.go Normal file
View File

@ -0,0 +1,14 @@
package lncfg
// AutoPilot holds the configuration options for the daemon's autopilot.
type AutoPilot struct {
Active bool `long:"active" description:"If the autopilot agent should be active or not."`
Heuristic map[string]float64 `long:"heuristic" description:"Heuristic to activate, and the weight to give it during scoring."`
MaxChannels int `long:"maxchannels" description:"The maximum number of channels that should be created"`
Allocation float64 `long:"allocation" description:"The percentage of total funds that should be committed to automatic channel establishment"`
MinChannelSize int64 `long:"minchansize" description:"The smallest channel that the autopilot agent should create"`
MaxChannelSize int64 `long:"maxchansize" description:"The largest channel that the autopilot agent should create"`
Private bool `long:"private" description:"Whether the channels created by the autopilot agent should be private or not. Private channels won't be announced to the network."`
MinConfs int32 `long:"minconfs" description:"The minimum number of confirmations each of your inputs in funding transactions created by the autopilot agent must have."`
ConfTarget uint32 `long:"conftarget" description:"The confirmation target (in blocks) for channels opened by autopilot."`
}

13
lncfg/bitcoind.go Normal file
View File

@ -0,0 +1,13 @@
package lncfg
// Bitcoind holds the configuration options for the daemon's connection to
// bitcoind.
type Bitcoind struct {
Dir string `long:"dir" description:"The base directory that contains the node's data, logs, configuration file, etc."`
RPCHost string `long:"rpchost" description:"The daemon's rpc listening address. If a port is omitted, then the default port for the selected chain parameters will be used."`
RPCUser string `long:"rpcuser" description:"Username for RPC connections"`
RPCPass string `long:"rpcpass" default-mask:"-" description:"Password for RPC connections"`
ZMQPubRawBlock string `long:"zmqpubrawblock" description:"The address listening for ZMQ connections to deliver raw block notifications"`
ZMQPubRawTx string `long:"zmqpubrawtx" description:"The address listening for ZMQ connections to deliver raw transaction notifications"`
EstimateMode string `long:"estimatemode" description:"The fee estimate mode. Must be either ECONOMICAL or CONSERVATIVE."`
}

11
lncfg/btcd.go Normal file
View File

@ -0,0 +1,11 @@
package lncfg
// Btcd holds the configuration options for the daemon's connection to btcd.
type Btcd struct {
Dir string `long:"dir" description:"The base directory that contains the node's data, logs, configuration file, etc."`
RPCHost string `long:"rpchost" description:"The daemon's rpc listening address. If a port is omitted, then the default port for the selected chain parameters will be used."`
RPCUser string `long:"rpcuser" description:"Username for RPC connections"`
RPCPass string `long:"rpcpass" default-mask:"-" description:"Password for RPC connections"`
RPCCert string `long:"rpccert" description:"File containing the daemon's certificate file"`
RawRPCCert string `long:"rawrpccert" description:"The raw bytes of the daemon's PEM-encoded certificate chain which will be used to authenticate the RPC connection."`
}

24
lncfg/chain.go Normal file
View File

@ -0,0 +1,24 @@
package lncfg
import "github.com/lightningnetwork/lnd/lnwire"
// Chain holds the configuration options for the daemon's chain settings.
type Chain struct {
Active bool `long:"active" description:"If the chain should be active or not."`
ChainDir string `long:"chaindir" description:"The directory to store the chain's data within."`
Node string `long:"node" description:"The blockchain interface to use." choice:"btcd" choice:"bitcoind" choice:"neutrino" choice:"ltcd" choice:"litecoind"`
MainNet bool `long:"mainnet" description:"Use the main network"`
TestNet3 bool `long:"testnet" description:"Use the test network"`
SimNet bool `long:"simnet" description:"Use the simulation test network"`
RegTest bool `long:"regtest" description:"Use the regression test network"`
DefaultNumChanConfs int `long:"defaultchanconfs" description:"The default number of confirmations a channel must have before it's considered open. If this is not set, we will scale the value according to the channel size."`
DefaultRemoteDelay int `long:"defaultremotedelay" description:"The default number of blocks we will require our channel counterparty to wait before accessing its funds in case of unilateral close. If this is not set, we will scale the value according to the channel size."`
MinHTLCIn lnwire.MilliSatoshi `long:"minhtlc" description:"The smallest HTLC we are willing to accept on our channels, in millisatoshi"`
MinHTLCOut lnwire.MilliSatoshi `long:"minhtlcout" description:"The smallest HTLC we are willing to send out on our channels, in millisatoshi"`
BaseFee lnwire.MilliSatoshi `long:"basefee" description:"The base fee in millisatoshi we will charge for forwarding payments on our channels"`
FeeRate lnwire.MilliSatoshi `long:"feerate" description:"The fee rate used when forwarding payments on our channels. The total fee charged is basefee + (amount * feerate / 1000000), where amount is the forwarded amount."`
TimeLockDelta uint32 `long:"timelockdelta" description:"The CLTV delta we will subtract from a forwarded HTLC's timelock value"`
}

89
lncfg/config.go Normal file
View File

@ -0,0 +1,89 @@
package lncfg
import (
"os"
"os/user"
"path/filepath"
"strings"
)
const (
// DefaultConfigFilename is the default configuration file name lnd
// tries to load.
DefaultConfigFilename = "lnd.conf"
// DefaultMaxPendingChannels is the default maximum number of incoming
// pending channels permitted per peer.
DefaultMaxPendingChannels = 1
// DefaultIncomingBroadcastDelta defines the number of blocks before the
// expiry of an incoming htlc at which we force close the channel. We
// only go to chain if we also have the preimage to actually pull in the
// htlc. BOLT #2 suggests 7 blocks. We use a few more for extra safety.
// Within this window we need to get our sweep or 2nd level success tx
// confirmed, because after that the remote party is also able to claim
// the htlc using the timeout path.
DefaultIncomingBroadcastDelta = 10
// DefaultFinalCltvRejectDelta defines the number of blocks before the
// expiry of an incoming exit hop htlc at which we cancel it back
// immediately. It is an extra safety measure over the final cltv
// requirement as it is defined in the invoice. It ensures that we
// cancel back htlcs that, when held on to, may cause us to force close
// the channel because we enter the incoming broadcast window. Bolt #11
// suggests 9 blocks here. We use a few more for additional safety.
//
// There is still a small gap that remains between receiving the
// RevokeAndAck and canceling back. If a new block arrives within that
// window, we may still force close the channel. There is currently no
// way to reject an UpdateAddHtlc of which we already know that it will
// push us in the broadcast window.
DefaultFinalCltvRejectDelta = DefaultIncomingBroadcastDelta + 3
// DefaultOutgoingBroadcastDelta defines the number of blocks before the
// expiry of an outgoing htlc at which we force close the channel. We
// are not in a hurry to force close, because there is nothing to claim
// for us. We do need to time the htlc out, because there may be an
// incoming htlc that will time out too (albeit later). Bolt #2 suggests
// a value of -1 here, but we allow one block less to prevent potential
// confusion around the negative value. It means we force close the
// channel at exactly the htlc expiry height.
DefaultOutgoingBroadcastDelta = 0
// DefaultOutgoingCltvRejectDelta defines the number of blocks before
// the expiry of an outgoing htlc at which we don't want to offer it to
// the next peer anymore. If that happens, we cancel back the incoming
// htlc. This is to prevent the situation where we have an outstanding
// htlc that brings or will soon bring us inside the outgoing broadcast
// window and trigger us to force close the channel. Bolt #2 suggests a
// value of 0. We pad it a bit, to prevent a slow round trip to the next
// peer and a block arriving during that round trip to trigger force
// closure.
DefaultOutgoingCltvRejectDelta = DefaultOutgoingBroadcastDelta + 3
)
// CleanAndExpandPath expands environment variables and leading ~ in the
// passed path, cleans the result, and returns it.
// This function is taken from https://github.com/btcsuite/btcd
func CleanAndExpandPath(path string) string {
if path == "" {
return ""
}
// Expand initial ~ to OS specific home directory.
if strings.HasPrefix(path, "~") {
var homeDir string
u, err := user.Current()
if err == nil {
homeDir = u.HomeDir
} else {
homeDir = os.Getenv("HOME")
}
path = strings.Replace(path, "~", homeDir, 1)
}
// NOTE: The os.ExpandEnv doesn't work with Windows-style %VARIABLE%,
// but the variables can still be expanded via POSIX-style $VARIABLE.
return filepath.Clean(os.ExpandEnv(path))
}

15
lncfg/neutrino.go Normal file
View File

@ -0,0 +1,15 @@
package lncfg
import "time"
// Neutrino holds the configuration options for the daemon's connection to
// neutrino.
type Neutrino struct {
AddPeers []string `short:"a" long:"addpeer" description:"Add a peer to connect with at startup"`
ConnectPeers []string `long:"connect" description:"Connect only to the specified peers at startup"`
MaxPeers int `long:"maxpeers" description:"Max number of inbound and outbound peers"`
BanDuration time.Duration `long:"banduration" description:"How long to ban misbehaving peers. Valid time units are {s, m, h}. Minimum 1 second"`
BanThreshold uint32 `long:"banthreshold" description:"Maximum allowed ban score before disconnecting and banning misbehaving peers."`
FeeURL string `long:"feeurl" description:"Optional URL for fee estimation. If a URL is not specified, static fees will be used for estimation."`
AssertFilterHeader string `long:"assertfilterheader" description:"Optional filter header in height:hash format to assert the state of neutrino's filter header chain on startup. If the assertion does not hold, then the filter header chain will be re-synced from the genesis block."`
}

16
lncfg/tor.go Normal file
View File

@ -0,0 +1,16 @@
package lncfg
// Tor holds the configuration options for the daemon's connection to tor.
type Tor struct {
Active bool `long:"active" description:"Allow outbound and inbound connections to be routed through Tor"`
SOCKS string `long:"socks" description:"The host:port that Tor's exposed SOCKS5 proxy is listening on"`
DNS string `long:"dns" description:"The DNS server as host:port that Tor will use for SRV queries - NOTE must have TCP resolution enabled"`
StreamIsolation bool `long:"streamisolation" description:"Enable Tor stream isolation by randomizing user credentials for each connection."`
Control string `long:"control" description:"The host:port that Tor is listening on for Tor control connections"`
TargetIPAddress string `long:"targetipaddress" description:"IP address that Tor should use as the target of the hidden service"`
Password string `long:"password" description:"The password used to arrive at the HashedControlPassword for the control port. If provided, the HASHEDPASSWORD authentication method will be used instead of the SAFECOOKIE one."`
V2 bool `long:"v2" description:"Automatically set up a v2 onion service to listen for inbound connections"`
V3 bool `long:"v3" description:"Automatically set up a v3 onion service to listen for inbound connections"`
PrivateKeyPath string `long:"privatekeypath" description:"The path to the private key of the onion service being created"`
WatchtowerKeyPath string `long:"watchtowerkeypath" description:"The path to the private key of the watchtower onion service being created"`
}

148
lnd.go
View File

@ -51,22 +51,12 @@ import (
"github.com/lightningnetwork/lnd/watchtower/wtdb"
)
var (
cfg *config
registeredChains = newChainRegistry()
// networkDir is the path to the directory of the currently active
// network. This path will hold the files related to each different
// network.
networkDir string
)
// WalletUnlockerAuthOptions returns a list of DialOptions that can be used to
// authenticate with the wallet unlocker service.
//
// NOTE: This should only be called after the WalletUnlocker listener has
// signaled it is ready.
func WalletUnlockerAuthOptions() ([]grpc.DialOption, error) {
func WalletUnlockerAuthOptions(cfg *Config) ([]grpc.DialOption, error) {
creds, err := credentials.NewClientTLSFromFile(cfg.TLSCertPath, "")
if err != nil {
return nil, fmt.Errorf("unable to read TLS cert: %v", err)
@ -85,7 +75,7 @@ func WalletUnlockerAuthOptions() ([]grpc.DialOption, error) {
//
// NOTE: This should only be called after the RPCListener has signaled it is
// ready.
func AdminAuthOptions() ([]grpc.DialOption, error) {
func AdminAuthOptions(cfg *Config) ([]grpc.DialOption, error) {
creds, err := credentials.NewClientTLSFromFile(cfg.TLSCertPath, "")
if err != nil {
return nil, fmt.Errorf("unable to read TLS cert: %v", err)
@ -119,6 +109,45 @@ func AdminAuthOptions() ([]grpc.DialOption, error) {
return opts, nil
}
// GrpcRegistrar is an interface that must be satisfied by an external subserver
// that wants to be able to register its own gRPC server onto lnd's main
// grpc.Server instance.
type GrpcRegistrar interface {
// RegisterGrpcSubserver is called for each net.Listener on which lnd
// creates a grpc.Server instance. External subservers implementing this
// method can then register their own gRPC server structs to the main
// server instance.
RegisterGrpcSubserver(*grpc.Server) error
}
// RestRegistrar is an interface that must be satisfied by an external subserver
// that wants to be able to register its own REST mux onto lnd's main
// proxy.ServeMux instance.
type RestRegistrar interface {
// RegisterRestSubserver is called after lnd creates the main
// proxy.ServeMux instance. External subservers implementing this method
// can then register their own REST proxy stubs to the main server
// instance.
RegisterRestSubserver(context.Context, *proxy.ServeMux, string,
[]grpc.DialOption) error
}
// RPCSubserverConfig is a struct that can be used to register an external
// subserver with the custom permissions that map to the gRPC server that is
// going to be registered with the GrpcRegistrar.
type RPCSubserverConfig struct {
// Registrar is a callback that is invoked for each net.Listener on
// which lnd creates a grpc.Server instance.
Registrar GrpcRegistrar
// Permissions is the permissions required for the external subserver.
// It is a map between the full HTTP URI of each RPC and its required
// macaroon permissions. If multiple action/entity tuples are specified
// per URI, they are all required. See rpcserver.go for a list of valid
// action and entity values.
Permissions map[string][]bakery.Op
}
// ListenerWithSignal is a net.Listener that has an additional Ready channel that
// will be closed when a server starts listening.
type ListenerWithSignal struct {
@ -126,6 +155,14 @@ type ListenerWithSignal struct {
// Ready will be closed by the server listening on Listener.
Ready chan struct{}
// ExternalRPCSubserverCfg is optional and specifies the registration
// callback and permissions to register external gRPC subservers.
ExternalRPCSubserverCfg *RPCSubserverConfig
// ExternalRestRegistrar is optional and specifies the registration
// callback to register external REST subservers.
ExternalRestRegistrar RestRegistrar
}
// ListenerCfg is a wrapper around custom listeners that can be passed to lnd
@ -147,23 +184,14 @@ type ListenerCfg struct {
// listeners.
type rpcListeners func() ([]*ListenerWithSignal, func(), error)
// Main is the true entry point for lnd. This function is required since defers
// created in the top-level scope of a main method aren't executed if os.Exit()
// is called.
func Main(lisCfg ListenerCfg) error {
// Hook interceptor for os signals.
signal.Intercept()
// Load the configuration, and parse any command line options. This
// function will also set up logging properly.
loadedConfig, err := loadConfig()
if err != nil {
return err
}
cfg = loadedConfig
// Main is the true entry point for lnd. It accepts a fully populated and
// validated main configuration struct and an optional listener config struct.
// This function starts all main system components then blocks until a signal
// is received on the shutdownChan at which point everything is shut down again.
func Main(cfg *Config, lisCfg ListenerCfg, shutdownChan <-chan struct{}) error {
defer func() {
ltndLog.Info("Shutdown complete")
err := logWriter.Close()
err := RootLogWriter.Close()
if err != nil {
ltndLog.Errorf("Could not close log rotator: %v", err)
}
@ -190,7 +218,7 @@ func Main(lisCfg ListenerCfg) error {
}
ltndLog.Infof("Active chain: %v (network=%v)",
strings.Title(registeredChains.PrimaryChain().String()),
strings.Title(cfg.registeredChains.PrimaryChain().String()),
network,
)
@ -256,10 +284,7 @@ func Main(lisCfg ListenerCfg) error {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
tlsCfg, restCreds, restProxyDest, err := getTLSConfig(
cfg.TLSCertPath, cfg.TLSKeyPath, cfg.TLSExtraIPs,
cfg.TLSExtraDomains, cfg.RPCListeners,
)
tlsCfg, restCreds, restProxyDest, err := getTLSConfig(cfg)
if err != nil {
err := fmt.Errorf("unable to load TLS credentials: %v", err)
ltndLog.Error(err)
@ -285,13 +310,13 @@ func Main(lisCfg ListenerCfg) error {
// light client instance, if enabled, in order to allow it to sync
// while the rest of the daemon continues startup.
mainChain := cfg.Bitcoin
if registeredChains.PrimaryChain() == litecoinChain {
if cfg.registeredChains.PrimaryChain() == litecoinChain {
mainChain = cfg.Litecoin
}
var neutrinoCS *neutrino.ChainService
if mainChain.Node == "neutrino" {
neutrinoBackend, neutrinoCleanUp, err := initNeutrinoBackend(
mainChain.ChainDir,
cfg, mainChain.ChainDir,
)
if err != nil {
err := fmt.Errorf("unable to initialize neutrino "+
@ -365,7 +390,7 @@ func Main(lisCfg ListenerCfg) error {
// for wallet encryption.
if !cfg.NoSeedBackup {
params, err := waitForWalletPassword(
cfg.RESTListeners, serverOpts, restDialOpts,
cfg, cfg.RESTListeners, serverOpts, restDialOpts,
restProxyDest, tlsCfg, walletUnlockerListeners,
)
if err != nil {
@ -390,7 +415,7 @@ func Main(lisCfg ListenerCfg) error {
if !cfg.NoMacaroons {
// Create the macaroon authentication/authorization service.
macaroonService, err = macaroons.NewService(
networkDir, macaroons.IPLockChecker,
cfg.networkDir, macaroons.IPLockChecker,
)
if err != nil {
err := fmt.Errorf("unable to set up macaroon "+
@ -442,8 +467,8 @@ func Main(lisCfg ListenerCfg) error {
// Finally before we start the server, we'll register the "holy
// trinity" of interface for our current "home chain" with the active
// chainRegistry interface.
primaryChain := registeredChains.PrimaryChain()
registeredChains.RegisterChain(primaryChain, activeChainControl)
primaryChain := cfg.registeredChains.PrimaryChain()
cfg.registeredChains.RegisterChain(primaryChain, activeChainControl)
// TODO(roasbeef): add rotation
idPrivKey, err := activeChainControl.wallet.DerivePrivKey(keychain.KeyDescriptor{
@ -507,7 +532,7 @@ func Main(lisCfg ListenerCfg) error {
// Segment the watchtower directory by chain and network.
towerDBDir := filepath.Join(
cfg.Watchtower.TowerDir,
registeredChains.PrimaryChain().String(),
cfg.registeredChains.PrimaryChain().String(),
normalizeNetwork(activeNetParams.Name),
)
@ -586,7 +611,7 @@ func Main(lisCfg ListenerCfg) error {
// Set up the core server which will listen for incoming peer
// connections.
server, err := newServer(
cfg.Listeners, chanDB, towerClientDB, activeChainControl,
cfg, cfg.Listeners, chanDB, towerClientDB, activeChainControl,
idPrivKey, walletInitParams.ChansToRestore, chainedAcceptor,
torController,
)
@ -636,7 +661,7 @@ func Main(lisCfg ListenerCfg) error {
// Initialize, and register our implementation of the gRPC interface
// exported by the rpcServer.
rpcServer, err := newRPCServer(
server, macaroonService, cfg.SubRPCServers, serverOpts,
cfg, server, macaroonService, cfg.SubRPCServers, serverOpts,
restDialOpts, restProxyDest, atplManager, server.invoices,
tower, tlsCfg, rpcListeners, chainedAcceptor,
)
@ -734,22 +759,21 @@ func Main(lisCfg ListenerCfg) error {
// Wait for shutdown signal from either a graceful server stop or from
// the interrupt handler.
<-signal.ShutdownChannel()
<-shutdownChan
return nil
}
// getTLSConfig returns a TLS configuration for the gRPC server and credentials
// and a proxy destination for the REST reverse proxy.
func getTLSConfig(tlsCertPath string, tlsKeyPath string, tlsExtraIPs,
tlsExtraDomains []string, rpcListeners []net.Addr) (*tls.Config,
*credentials.TransportCredentials, string, error) {
func getTLSConfig(cfg *Config) (*tls.Config, *credentials.TransportCredentials,
string, error) {
// Ensure we create TLS key and certificate if they don't exist.
if !fileExists(tlsCertPath) && !fileExists(tlsKeyPath) {
if !fileExists(cfg.TLSCertPath) && !fileExists(cfg.TLSKeyPath) {
rpcsLog.Infof("Generating TLS certificates...")
err := cert.GenCertPair(
"lnd autogenerated cert", tlsCertPath, tlsKeyPath,
tlsExtraIPs, tlsExtraDomains,
"lnd autogenerated cert", cfg.TLSCertPath,
cfg.TLSKeyPath, cfg.TLSExtraIPs, cfg.TLSExtraDomains,
cert.DefaultAutogenValidity,
)
if err != nil {
@ -758,7 +782,9 @@ func getTLSConfig(tlsCertPath string, tlsKeyPath string, tlsExtraIPs,
rpcsLog.Infof("Done generating TLS certificates")
}
certData, parsedCert, err := cert.LoadCert(tlsCertPath, tlsKeyPath)
certData, parsedCert, err := cert.LoadCert(
cfg.TLSCertPath, cfg.TLSKeyPath,
)
if err != nil {
return nil, nil, "", err
}
@ -770,7 +796,7 @@ func getTLSConfig(tlsCertPath string, tlsKeyPath string, tlsExtraIPs,
refresh := false
if cfg.TLSAutoRefresh {
refresh, err = cert.IsOutdated(
parsedCert, tlsExtraIPs, tlsExtraDomains,
parsedCert, cfg.TLSExtraIPs, cfg.TLSExtraDomains,
)
if err != nil {
return nil, nil, "", err
@ -783,20 +809,20 @@ func getTLSConfig(tlsCertPath string, tlsKeyPath string, tlsExtraIPs,
ltndLog.Info("TLS certificate is expired or outdated, " +
"generating a new one")
err := os.Remove(tlsCertPath)
err := os.Remove(cfg.TLSCertPath)
if err != nil {
return nil, nil, "", err
}
err = os.Remove(tlsKeyPath)
err = os.Remove(cfg.TLSKeyPath)
if err != nil {
return nil, nil, "", err
}
rpcsLog.Infof("Renewing TLS certificates...")
err = cert.GenCertPair(
"lnd autogenerated cert", tlsCertPath, tlsKeyPath,
tlsExtraIPs, tlsExtraDomains,
"lnd autogenerated cert", cfg.TLSCertPath,
cfg.TLSKeyPath, cfg.TLSExtraIPs, cfg.TLSExtraDomains,
cert.DefaultAutogenValidity,
)
if err != nil {
@ -805,19 +831,21 @@ func getTLSConfig(tlsCertPath string, tlsKeyPath string, tlsExtraIPs,
rpcsLog.Infof("Done renewing TLS certificates")
// Reload the certificate data.
certData, _, err = cert.LoadCert(tlsCertPath, tlsKeyPath)
certData, _, err = cert.LoadCert(
cfg.TLSCertPath, cfg.TLSKeyPath,
)
if err != nil {
return nil, nil, "", err
}
}
tlsCfg := cert.TLSConfFromCert(certData)
restCreds, err := credentials.NewClientTLSFromFile(tlsCertPath, "")
restCreds, err := credentials.NewClientTLSFromFile(cfg.TLSCertPath, "")
if err != nil {
return nil, nil, "", err
}
restProxyDest := rpcListeners[0].String()
restProxyDest := cfg.RPCListeners[0].String()
switch {
case strings.Contains(restProxyDest, "0.0.0.0"):
restProxyDest = strings.Replace(
@ -934,7 +962,7 @@ type WalletUnlockParams struct {
// waitForWalletPassword will spin up gRPC and REST endpoints for the
// WalletUnlocker server, and block until a password is provided by
// the user to this RPC server.
func waitForWalletPassword(restEndpoints []net.Addr,
func waitForWalletPassword(cfg *Config, restEndpoints []net.Addr,
serverOpts []grpc.ServerOption, restDialOpts []grpc.DialOption,
restProxyDest string, tlsConf *tls.Config,
getListeners rpcListeners) (*WalletUnlockParams, error) {
@ -953,7 +981,7 @@ func waitForWalletPassword(restEndpoints []net.Addr,
defer grpcServer.GracefulStop()
chainConfig := cfg.Bitcoin
if registeredChains.PrimaryChain() == litecoinChain {
if cfg.registeredChains.PrimaryChain() == litecoinChain {
chainConfig = cfg.Litecoin
}
@ -962,7 +990,7 @@ func waitForWalletPassword(restEndpoints []net.Addr,
// deleted within it and recreated when successfully changing the
// wallet's password.
macaroonFiles := []string{
filepath.Join(networkDir, macaroons.DBFilename),
filepath.Join(cfg.networkDir, macaroons.DBFilename),
cfg.AdminMacPath, cfg.ReadMacPath, cfg.InvoiceMacPath,
}
pwService := walletunlocker.New(

View File

@ -10,6 +10,7 @@ import (
"github.com/btcsuite/btcd/wire"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lntest"
@ -136,7 +137,7 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest,
// We'll now mine enough blocks so Carol decides that she needs to go
// on-chain to claim the HTLC as Bob has been inactive.
numBlocks := padCLTV(uint32(invoiceReq.CltvExpiry -
lnd.DefaultIncomingBroadcastDelta))
lncfg.DefaultIncomingBroadcastDelta))
if _, err := net.Miner.Node.Generate(numBlocks); err != nil {
t.Fatalf("unable to generate blocks")

View File

@ -12,6 +12,7 @@ import (
"github.com/btcsuite/btcutil"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/wait"
@ -101,7 +102,7 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest,
// timeout. With the default outgoing broadcast delta of zero, this will
// be the same height as the htlc expiry height.
numBlocks := padCLTV(
uint32(finalCltvDelta - lnd.DefaultOutgoingBroadcastDelta),
uint32(finalCltvDelta - lncfg.DefaultOutgoingBroadcastDelta),
)
if _, err := net.Miner.Node.Generate(numBlocks); err != nil {
t.Fatalf("unable to generate blocks: %v", err)

View File

@ -10,6 +10,7 @@ import (
"github.com/btcsuite/btcd/wire"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lntest"
@ -118,7 +119,7 @@ func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest,
// chain in order to sweep her HTLC since the value is high enough.
// TODO(roasbeef): modify once go to chain policy changes
numBlocks := padCLTV(uint32(
invoiceReq.CltvExpiry - lnd.DefaultIncomingBroadcastDelta,
invoiceReq.CltvExpiry - lncfg.DefaultIncomingBroadcastDelta,
))
if _, err := net.Miner.Node.Generate(numBlocks); err != nil {
t.Fatalf("unable to generate blocks")

View File

@ -10,6 +10,7 @@ import (
"github.com/btcsuite/btcd/wire"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lntest"
@ -148,7 +149,7 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest
// We'll now mine enough blocks so Carol decides that she needs to go
// on-chain to claim the HTLC as Bob has been inactive.
numBlocks := padCLTV(uint32(invoiceReq.CltvExpiry-
lnd.DefaultIncomingBroadcastDelta) - defaultCSV)
lncfg.DefaultIncomingBroadcastDelta) - defaultCSV)
if _, err := net.Miner.Node.Generate(numBlocks); err != nil {
t.Fatalf("unable to generate blocks")

View File

@ -34,6 +34,7 @@ import (
"github.com/lightningnetwork/lnd/chanbackup"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
@ -6695,7 +6696,7 @@ func testBasicChannelCreationAndUpdates(net *lntest.NetworkHarness, t *harnessTe
func testMaxPendingChannels(net *lntest.NetworkHarness, t *harnessTest) {
ctxb := context.Background()
maxPendingChannels := lnd.DefaultMaxPendingChannels + 1
maxPendingChannels := lncfg.DefaultMaxPendingChannels + 1
amount := lnd.MaxBtcFundingAmount
// Create a new node (Carol) with greater number of max pending

26
log.go
View File

@ -46,21 +46,23 @@ import (
//
// Loggers can not be used before the log rotator has been initialized with a
// log file. This must be performed early during application startup by
// calling logWriter.InitLogRotator.
// calling RootLogWriter.InitLogRotator.
var (
logWriter = build.NewRotatingLogWriter()
// RootLogWriter is the main parent log writer all sub loggers should be
// appended to.
RootLogWriter = build.NewRotatingLogWriter()
// Loggers that need to be accessible from the lnd package can be placed
// here. Loggers that are only used in sub modules can be added directly
// by using the addSubLogger method.
ltndLog = build.NewSubLogger("LTND", logWriter.GenSubLogger)
peerLog = build.NewSubLogger("PEER", logWriter.GenSubLogger)
rpcsLog = build.NewSubLogger("RPCS", logWriter.GenSubLogger)
srvrLog = build.NewSubLogger("SRVR", logWriter.GenSubLogger)
fndgLog = build.NewSubLogger("FNDG", logWriter.GenSubLogger)
utxnLog = build.NewSubLogger("UTXN", logWriter.GenSubLogger)
brarLog = build.NewSubLogger("BRAR", logWriter.GenSubLogger)
atplLog = build.NewSubLogger("ATPL", logWriter.GenSubLogger)
ltndLog = build.NewSubLogger("LTND", RootLogWriter.GenSubLogger)
peerLog = build.NewSubLogger("PEER", RootLogWriter.GenSubLogger)
rpcsLog = build.NewSubLogger("RPCS", RootLogWriter.GenSubLogger)
srvrLog = build.NewSubLogger("SRVR", RootLogWriter.GenSubLogger)
fndgLog = build.NewSubLogger("FNDG", RootLogWriter.GenSubLogger)
utxnLog = build.NewSubLogger("UTXN", RootLogWriter.GenSubLogger)
brarLog = build.NewSubLogger("BRAR", RootLogWriter.GenSubLogger)
atplLog = build.NewSubLogger("ATPL", RootLogWriter.GenSubLogger)
)
// Initialize package-global logger variables.
@ -110,7 +112,7 @@ func init() {
func addSubLogger(subsystem string, useLoggers ...func(btclog.Logger)) {
// Create and register just a single logger to prevent them from
// overwriting each other internally.
logger := build.NewSubLogger(subsystem, logWriter.GenSubLogger)
logger := build.NewSubLogger(subsystem, RootLogWriter.GenSubLogger)
setSubLogger(subsystem, logger, useLoggers...)
}
@ -119,7 +121,7 @@ func addSubLogger(subsystem string, useLoggers ...func(btclog.Logger)) {
func setSubLogger(subsystem string, logger btclog.Logger,
useLoggers ...func(btclog.Logger)) {
logWriter.RegisterSubLogger(subsystem, logger)
RootLogWriter.RegisterSubLogger(subsystem, logger)
for _, useLogger := range useLoggers {
useLogger(logger)
}

14
peer.go
View File

@ -114,6 +114,8 @@ type peer struct {
started int32
disconnect int32
cfg *Config
// The following fields are only meant to be used *atomically*
bytesReceived uint64
bytesSent uint64
@ -263,7 +265,7 @@ var _ lnpeer.Peer = (*peer)(nil)
// pointer to the main server. It takes an error buffer which may contain errors
// from a previous connection with the peer if we have been connected to them
// before.
func newPeer(conn net.Conn, connReq *connmgr.ConnReq, server *server,
func newPeer(cfg *Config, conn net.Conn, connReq *connmgr.ConnReq, server *server,
addr *lnwire.NetAddress, inbound bool,
features, legacyFeatures *lnwire.FeatureVector,
chanActiveTimeout time.Duration,
@ -277,6 +279,8 @@ func newPeer(conn net.Conn, connReq *connmgr.ConnReq, server *server,
conn: conn,
addr: addr,
cfg: cfg,
activeSignal: make(chan struct{}),
inbound: inbound,
@ -651,7 +655,7 @@ func (p *peer) addLink(chanPoint *wire.OutPoint,
DecodeHopIterators: p.server.sphinx.DecodeHopIterators,
ExtractErrorEncrypter: p.server.sphinx.ExtractErrorEncrypter,
FetchLastChannelUpdate: p.server.fetchLastChanUpdate(),
HodlMask: cfg.Hodl.Mask(),
HodlMask: p.cfg.Hodl.Mask(),
Registry: p.server.invoices,
Switch: p.server.htlcSwitch,
Circuits: p.server.htlcSwitch.CircuitModifier(),
@ -671,13 +675,13 @@ func (p *peer) addLink(chanPoint *wire.OutPoint,
FwdPkgGCTicker: ticker.New(time.Minute),
PendingCommitTicker: ticker.New(time.Minute),
BatchSize: 10,
UnsafeReplay: cfg.UnsafeReplay,
UnsafeReplay: p.cfg.UnsafeReplay,
MinFeeUpdateTimeout: htlcswitch.DefaultMinLinkFeeUpdateTimeout,
MaxFeeUpdateTimeout: htlcswitch.DefaultMaxLinkFeeUpdateTimeout,
OutgoingCltvRejectDelta: p.outgoingCltvRejectDelta,
TowerClient: p.server.towerClient,
MaxOutgoingCltvExpiry: cfg.MaxOutgoingCltvExpiry,
MaxFeeAllocation: cfg.MaxChannelFeeAllocation,
MaxOutgoingCltvExpiry: p.cfg.MaxOutgoingCltvExpiry,
MaxFeeAllocation: p.cfg.MaxChannelFeeAllocation,
NotifyActiveLink: p.server.channelNotifier.NotifyActiveLinkEvent,
NotifyActiveChannel: p.server.channelNotifier.NotifyActiveChannelEvent,
NotifyInactiveChannel: p.server.channelNotifier.NotifyInactiveChannelEvent,

View File

@ -9,6 +9,7 @@ import (
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/autopilot"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/tor"
)
@ -17,7 +18,7 @@ import (
// configuration is sane. Currently it checks that the heuristic configuration
// makes sense. In case the config is valid, it will return a list of
// WeightedHeuristics that can be combined for use with the autopilot agent.
func validateAtplCfg(cfg *autoPilotConfig) ([]*autopilot.WeightedHeuristic,
func validateAtplCfg(cfg *lncfg.AutoPilot) ([]*autopilot.WeightedHeuristic,
error) {
var (
@ -138,8 +139,8 @@ var _ autopilot.ChannelController = (*chanController)(nil)
// Agent instance based on the passed configuration structs. The agent and all
// interfaces needed to drive it won't be launched before the Manager's
// StartAgent method is called.
func initAutoPilot(svr *server, cfg *autoPilotConfig, chainCfg *chainConfig) (
*autopilot.ManagerCfg, error) {
func initAutoPilot(svr *server, cfg *lncfg.AutoPilot,
chainCfg *lncfg.Chain) (*autopilot.ManagerCfg, error) {
atplLog.Infof("Instantiating autopilot with active=%v, "+
"max_channels=%d, allocation=%f, min_chan_size=%d, "+

View File

@ -461,6 +461,8 @@ type rpcServer struct {
server *server
cfg *Config
// subServers are a set of sub-RPC servers that use the same gRPC and
// listening sockets as the main RPC server, but which maintain their
// own independent service. This allows us to expose a set of
@ -521,7 +523,7 @@ var _ lnrpc.LightningServer = (*rpcServer)(nil)
// of the sub-servers that it maintains. The set of serverOpts should be the
// base level options passed to the grPC server. This typically includes things
// like requiring TLS, etc.
func newRPCServer(s *server, macService *macaroons.Service,
func newRPCServer(cfg *Config, s *server, macService *macaroons.Service,
subServerCgs *subRPCServerConfigs, serverOpts []grpc.ServerOption,
restDialOpts []grpc.DialOption, restProxyDest string,
atpl *autopilot.Manager, invoiceRegistry *invoices.InvoiceRegistry,
@ -585,7 +587,7 @@ func newRPCServer(s *server, macService *macaroons.Service,
// the dependencies they need are properly populated within each sub
// server configuration struct.
err = subServerCgs.PopulateDependencies(
s.cc, networkDir, macService, atpl, invoiceRegistry,
cfg, s.cc, cfg.networkDir, macService, atpl, invoiceRegistry,
s.htlcSwitch, activeNetParams.Params, s.chanRouter,
routerBackend, s.nodeSigner, s.chanDB, s.sweeper, tower,
s.towerClient, cfg.net.ResolveTCPAddr, genInvoiceFeatures,
@ -629,6 +631,32 @@ func newRPCServer(s *server, macService *macaroons.Service,
}
}
// Get the listeners and server options to use for this rpc server.
listeners, cleanup, err := getListeners()
if err != nil {
return nil, err
}
// External subserver possibly need to register their own permissions.
for _, lis := range listeners {
extSubserver := lis.ExternalRPCSubserverCfg
if extSubserver != nil {
for method, ops := range extSubserver.Permissions {
// For each new method:ops combo, we also ensure
// that non of the sub-servers try to override
// each other.
if _, ok := permissions[method]; ok {
return nil, fmt.Errorf("detected "+
"duplicate macaroon "+
"constraints for path: %v",
method)
}
permissions[method] = ops
}
}
}
// If macaroons aren't disabled (a non-nil service), then we'll set up
// our set of interceptors which will allow us to handle the macaroon
// authentication in a single location.
@ -660,12 +688,6 @@ func newRPCServer(s *server, macService *macaroons.Service,
strmInterceptors, errorLogStreamServerInterceptor(rpcsLog),
)
// Get the listeners and server options to use for this rpc server.
listeners, cleanup, err := getListeners()
if err != nil {
return nil, err
}
// If any interceptors have been set up, add them to the server options.
if len(unaryInterceptors) != 0 && len(strmInterceptors) != 0 {
chainedUnary := grpc_middleware.WithUnaryServerChain(
@ -681,6 +703,7 @@ func newRPCServer(s *server, macService *macaroons.Service,
// gRPC server, and register the main lnrpc server along side.
grpcServer := grpc.NewServer(serverOpts...)
rootRPCServer := &rpcServer{
cfg: cfg,
restDialOpts: restDialOpts,
listeners: listeners,
listenerCleanUp: []func(){cleanup},
@ -737,16 +760,36 @@ func (r *rpcServer) Start() error {
go func(lis *ListenerWithSignal) {
rpcsLog.Infof("RPC server listening on %s", lis.Addr())
// Before actually listening on the gRPC listener, give
// external subservers the chance to register to our
// gRPC server. Those external subservers (think GrUB)
// are responsible for starting/stopping on their own,
// we just let them register their services to the same
// server instance so all of them can be exposed on the
// same port/listener.
extSubCfg := lis.ExternalRPCSubserverCfg
if extSubCfg != nil && extSubCfg.Registrar != nil {
registerer := extSubCfg.Registrar
err := registerer.RegisterGrpcSubserver(
r.grpcServer,
)
if err != nil {
rpcsLog.Errorf("error registering "+
"external gRPC subserver: %v",
err)
}
}
// Close the ready chan to indicate we are listening.
close(lis.Ready)
r.grpcServer.Serve(lis)
_ = r.grpcServer.Serve(lis)
}(lis)
}
// If Prometheus monitoring is enabled, start the Prometheus exporter.
if cfg.Prometheus.Enabled() {
if r.cfg.Prometheus.Enabled() {
err := monitoring.ExportPrometheusMetrics(
r.grpcServer, cfg.Prometheus,
r.grpcServer, r.cfg.Prometheus,
)
if err != nil {
return err
@ -771,32 +814,50 @@ func (r *rpcServer) Start() error {
//
// TODO(roasbeef): eventually also allow the sub-servers to themselves
// have a REST proxy.
mux := proxy.NewServeMux(customMarshalerOption)
restMux := proxy.NewServeMux(customMarshalerOption)
restCtx, restCancel := context.WithCancel(context.Background())
r.listenerCleanUp = append(r.listenerCleanUp, restCancel)
err := lnrpc.RegisterLightningHandlerFromEndpoint(
context.Background(), mux, r.restProxyDest,
r.restDialOpts,
restCtx, restMux, r.restProxyDest, r.restDialOpts,
)
if err != nil {
return err
}
for _, restEndpoint := range cfg.RESTListeners {
// Before listening on any of the interfaces, we also want to give the
// external subservers a chance to register their own REST proxy stub
// with our mux instance.
for _, lis := range r.listeners {
if lis.ExternalRestRegistrar != nil {
err := lis.ExternalRestRegistrar.RegisterRestSubserver(
restCtx, restMux, r.restProxyDest,
r.restDialOpts,
)
if err != nil {
rpcsLog.Errorf("error registering "+
"external REST subserver: %v", err)
}
}
}
// Now spin up a network listener for each requested port and start a
// goroutine that serves REST with the created mux there.
for _, restEndpoint := range r.cfg.RESTListeners {
lis, err := lncfg.TLSListenOnAddress(restEndpoint, r.tlsCfg)
if err != nil {
ltndLog.Errorf(
"gRPC proxy unable to listen on %s",
restEndpoint,
)
ltndLog.Errorf("gRPC proxy unable to listen on %s",
restEndpoint)
return err
}
r.listenerCleanUp = append(r.listenerCleanUp, func() {
lis.Close()
_ = lis.Close()
})
go func() {
rpcsLog.Infof("gRPC proxy started at %s", lis.Addr())
http.Serve(lis, mux)
_ = http.Serve(lis, restMux)
}()
}
@ -1363,7 +1424,7 @@ func (r *rpcServer) ConnectPeer(ctx context.Context,
return nil, fmt.Errorf("cannot make connection to self")
}
addr, err := parseAddr(in.Addr.Host)
addr, err := parseAddr(in.Addr.Host, r.cfg.net)
if err != nil {
return nil, err
}
@ -1420,7 +1481,7 @@ func (r *rpcServer) DisconnectPeer(ctx context.Context,
// In order to avoid erroneously disconnecting from a peer that we have
// an active channel with, if we have any channels active with this
// peer, then we'll disallow disconnecting from them.
if len(nodeChannels) > 0 && !cfg.UnsafeDisconnect {
if len(nodeChannels) > 0 && !r.cfg.UnsafeDisconnect {
return nil, fmt.Errorf("cannot disconnect from peer(%x), "+
"all active channels with the peer need to be closed "+
"first", pubKeyBytes)
@ -2347,8 +2408,8 @@ func (r *rpcServer) GetInfo(ctx context.Context,
}
network := normalizeNetwork(activeNetParams.Name)
activeChains := make([]*lnrpc.Chain, registeredChains.NumActiveChains())
for i, chain := range registeredChains.ActiveChains() {
activeChains := make([]*lnrpc.Chain, r.cfg.registeredChains.NumActiveChains())
for i, chain := range r.cfg.registeredChains.ActiveChains() {
activeChains[i] = &lnrpc.Chain{
Chain: chain.String(),
Network: network,
@ -3756,7 +3817,7 @@ func (r *rpcServer) extractPaymentIntent(rpcPayReq *rpcPaymentRequest) (rpcPayme
// Take the CLTV limit from the request if set, otherwise use the max.
cltvLimit, err := routerrpc.ValidateCLTVLimit(
rpcPayReq.CltvLimit, cfg.MaxOutgoingCltvExpiry,
rpcPayReq.CltvLimit, r.cfg.MaxOutgoingCltvExpiry,
)
if err != nil {
return payIntent, err
@ -3885,7 +3946,7 @@ func (r *rpcServer) extractPaymentIntent(rpcPayReq *rpcPaymentRequest) (rpcPayme
// use when creating an invoice. We do not assume the default of
// 9 blocks that is defined in BOLT-11, because this is never
// enough for other lnd nodes.
payIntent.cltvDelta = uint16(cfg.Bitcoin.TimeLockDelta)
payIntent.cltvDelta = uint16(r.cfg.Bitcoin.TimeLockDelta)
}
// If the user is manually specifying payment details, then the payment
@ -4307,9 +4368,9 @@ func (r *rpcServer) sendPaymentSync(ctx context.Context,
func (r *rpcServer) AddInvoice(ctx context.Context,
invoice *lnrpc.Invoice) (*lnrpc.AddInvoiceResponse, error) {
defaultDelta := cfg.Bitcoin.TimeLockDelta
if registeredChains.PrimaryChain() == litecoinChain {
defaultDelta = cfg.Litecoin.TimeLockDelta
defaultDelta := r.cfg.Bitcoin.TimeLockDelta
if r.cfg.registeredChains.PrimaryChain() == litecoinChain {
defaultDelta = r.cfg.Litecoin.TimeLockDelta
}
addInvoiceCfg := &invoicesrpc.AddInvoiceConfig{
@ -5221,7 +5282,7 @@ func (r *rpcServer) DebugLevel(ctx context.Context,
if req.Show {
return &lnrpc.DebugLevelResponse{
SubSystems: strings.Join(
logWriter.SupportedSubsystems(), " ",
RootLogWriter.SupportedSubsystems(), " ",
),
}, nil
}
@ -5230,7 +5291,7 @@ func (r *rpcServer) DebugLevel(ctx context.Context,
// Otherwise, we'll attempt to set the logging level using the
// specified level spec.
err := build.ParseAndSetDebugLevels(req.LevelSpec, logWriter)
err := build.ParseAndSetDebugLevels(req.LevelSpec, RootLogWriter)
if err != nil {
return nil, err
}
@ -6013,14 +6074,14 @@ func (r *rpcServer) ChannelAcceptor(stream lnrpc.Lightning_ChannelAcceptorServer
}
// timeout is the time after which ChannelAcceptRequests expire.
timeout := time.After(cfg.AcceptorTimeout)
timeout := time.After(r.cfg.AcceptorTimeout)
// Send the request to the newRequests channel.
select {
case newRequests <- newRequest:
case <-timeout:
rpcsLog.Errorf("RPCAcceptor returned false - reached timeout of %d",
cfg.AcceptorTimeout)
r.cfg.AcceptorTimeout)
return false
case <-quit:
return false
@ -6035,7 +6096,7 @@ func (r *rpcServer) ChannelAcceptor(stream lnrpc.Lightning_ChannelAcceptorServer
return resp
case <-timeout:
rpcsLog.Errorf("RPCAcceptor returned false - reached timeout of %d",
cfg.AcceptorTimeout)
r.cfg.AcceptorTimeout)
return false
case <-quit:
return false

View File

@ -133,6 +133,8 @@ type server struct {
start sync.Once
stop sync.Once
cfg *Config
// identityPriv is the private key used to authenticate any incoming
// connections.
identityPriv *btcec.PrivateKey
@ -272,7 +274,7 @@ type server struct {
}
// parseAddr parses an address from its string format to a net.Addr.
func parseAddr(address string) (net.Addr, error) {
func parseAddr(address string, netCfg tor.Net) (net.Addr, error) {
var (
host string
port int
@ -304,21 +306,23 @@ func parseAddr(address string) (net.Addr, error) {
// addresses over Tor in order to prevent leaking your real IP
// address.
hostPort := net.JoinHostPort(host, strconv.Itoa(port))
return cfg.net.ResolveTCPAddr("tcp", hostPort)
return netCfg.ResolveTCPAddr("tcp", hostPort)
}
// noiseDial is a factory function which creates a connmgr compliant dialing
// function by returning a closure which includes the server's identity key.
func noiseDial(idPriv *btcec.PrivateKey) func(net.Addr) (net.Conn, error) {
func noiseDial(idPriv *btcec.PrivateKey,
netCfg tor.Net) func(net.Addr) (net.Conn, error) {
return func(a net.Addr) (net.Conn, error) {
lnAddr := a.(*lnwire.NetAddress)
return brontide.Dial(idPriv, lnAddr, cfg.net.Dial)
return brontide.Dial(idPriv, lnAddr, netCfg.Dial)
}
}
// newServer creates a new instance of the server which is to listen using the
// passed listener address.
func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
towerClientDB *wtdb.ClientDB, cc *chainControl,
privKey *btcec.PrivateKey,
chansToRestore walletunlocker.ChannelsToRecover,
@ -399,13 +403,14 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
}
registryConfig := invoices.RegistryConfig{
FinalCltvRejectDelta: defaultFinalCltvRejectDelta,
FinalCltvRejectDelta: lncfg.DefaultFinalCltvRejectDelta,
HtlcHoldDuration: invoices.DefaultHtlcHoldDuration,
Clock: clock.NewDefaultClock(),
AcceptKeySend: cfg.AcceptKeySend,
}
s := &server{
cfg: cfg,
chanDB: chanDB,
cc: cc,
sigPool: lnwallet.NewSigPool(cfg.Workers.Sig, cc.signer),
@ -867,8 +872,8 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
s.chainArb = contractcourt.NewChainArbitrator(contractcourt.ChainArbitratorConfig{
ChainHash: *activeNetParams.GenesisHash,
IncomingBroadcastDelta: DefaultIncomingBroadcastDelta,
OutgoingBroadcastDelta: DefaultOutgoingBroadcastDelta,
IncomingBroadcastDelta: lncfg.DefaultIncomingBroadcastDelta,
OutgoingBroadcastDelta: lncfg.DefaultOutgoingBroadcastDelta,
NewSweepAddr: newSweepPkScriptGen(cc.wallet),
PublishTx: cc.wallet.PublishTransaction,
DeliverResolutionMsg: func(msgs ...contractcourt.ResolutionMsg) error {
@ -959,7 +964,7 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
// Select the configuration and furnding parameters for Bitcoin or
// Litecoin, depending on the primary registered chain.
primaryChain := registeredChains.PrimaryChain()
primaryChain := cfg.registeredChains.PrimaryChain()
chainCfg := cfg.Bitcoin
minRemoteDelay := minBtcRemoteDelay
maxRemoteDelay := maxBtcRemoteDelay
@ -1144,6 +1149,8 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
NotifyOpenChannelEvent: s.channelNotifier.NotifyOpenChannelEvent,
OpenChannelPredicate: chanPredicate,
NotifyPendingOpenChannelEvent: s.channelNotifier.NotifyPendingOpenChannelEvent,
EnableUpfrontShutdown: cfg.EnableUpfrontShutdown,
RegisteredChains: cfg.registeredChains,
})
if err != nil {
return nil, err
@ -1220,7 +1227,7 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
OnAccept: s.InboundPeerConnected,
RetryDuration: time.Second * 5,
TargetOutbound: 100,
Dial: noiseDial(s.identityPriv),
Dial: noiseDial(s.identityPriv, s.cfg.net),
OnConnection: s.OutboundPeerConnected,
})
if err != nil {
@ -1402,8 +1409,9 @@ func (s *server) Start() error {
// configure the set of active bootstrappers, and launch a
// dedicated goroutine to maintain a set of persistent
// connections.
if !cfg.NoNetBootstrap && !(cfg.Bitcoin.SimNet || cfg.Litecoin.SimNet) &&
!(cfg.Bitcoin.RegTest || cfg.Litecoin.RegTest) {
if !s.cfg.NoNetBootstrap &&
!(s.cfg.Bitcoin.SimNet || s.cfg.Litecoin.SimNet) &&
!(s.cfg.Bitcoin.RegTest || s.cfg.Litecoin.RegTest) {
bootstrappers, err := initNetworkBootstrappers(s)
if err != nil {
@ -1546,7 +1554,7 @@ func (s *server) watchExternalIP() {
// Keep track of the external IPs set by the user to avoid replacing
// them when detecting a new IP.
ipsSetByUser := make(map[string]struct{})
for _, ip := range cfg.ExternalIPs {
for _, ip := range s.cfg.ExternalIPs {
ipsSetByUser[ip.String()] = struct{}{}
}
@ -1690,7 +1698,7 @@ func initNetworkBootstrappers(s *server) ([]discovery.NetworkPeerBootstrapper, e
// If this isn't simnet mode, then one of our additional bootstrapping
// sources will be the set of running DNS seeds.
if !cfg.Bitcoin.SimNet || !cfg.Litecoin.SimNet {
if !s.cfg.Bitcoin.SimNet || !s.cfg.Litecoin.SimNet {
dnsSeeds, ok := chainDNSSeeds[*activeNetParams.GenesisHash]
// If we have a set of DNS seeds for this chain, then we'll add
@ -1700,7 +1708,7 @@ func initNetworkBootstrappers(s *server) ([]discovery.NetworkPeerBootstrapper, e
"seeds: %v", dnsSeeds)
dnsBootStrapper := discovery.NewDNSSeedBootstrapper(
dnsSeeds, cfg.net,
dnsSeeds, s.cfg.net,
)
bootStrappers = append(bootStrappers, dnsBootStrapper)
}
@ -1972,13 +1980,13 @@ func (s *server) createNewHiddenService() error {
onionCfg := tor.AddOnionConfig{
VirtualPort: defaultPeerPort,
TargetPorts: listenPorts,
Store: tor.NewOnionFile(cfg.Tor.PrivateKeyPath, 0600),
Store: tor.NewOnionFile(s.cfg.Tor.PrivateKeyPath, 0600),
}
switch {
case cfg.Tor.V2:
case s.cfg.Tor.V2:
onionCfg.Type = tor.V2
case cfg.Tor.V3:
case s.cfg.Tor.V3:
onionCfg.Type = tor.V3
}
@ -2131,7 +2139,7 @@ func (s *server) establishPersistentConnections() error {
// We'll only attempt to connect to Tor addresses if Tor
// outbound support is enabled.
case *tor.OnionAddr:
if cfg.Tor.Active {
if s.cfg.Tor.Active {
addrSet[addr.String()] = addr
}
}
@ -2149,7 +2157,7 @@ func (s *server) establishPersistentConnections() error {
// We'll only attempt to connect to Tor
// addresses if Tor outbound support is enabled.
case *tor.OnionAddr:
if cfg.Tor.Active {
if s.cfg.Tor.Active {
addrSet[lnAddress.String()] = lnAddress
}
}
@ -2193,7 +2201,7 @@ func (s *server) establishPersistentConnections() error {
// been requested as perm by the user.
s.persistentPeers[pubStr] = false
if _, ok := s.persistentPeersBackoff[pubStr]; !ok {
s.persistentPeersBackoff[pubStr] = cfg.MinBackoff
s.persistentPeersBackoff[pubStr] = s.cfg.MinBackoff
}
for _, address := range nodeAddr.addresses {
@ -2226,7 +2234,7 @@ func (s *server) establishPersistentConnections() error {
// nodes are able to disperse the costs of connecting to
// all peers at once.
if numOutboundConns < numInstantInitReconnect ||
!cfg.StaggerInitialReconnect {
!s.cfg.StaggerInitialReconnect {
go s.connMgr.Connect(connReq)
} else {
@ -2435,14 +2443,14 @@ func (s *server) nextPeerBackoff(pubStr string,
backoff, ok := s.persistentPeersBackoff[pubStr]
if !ok {
// If an existing backoff was unknown, use the default.
return cfg.MinBackoff
return s.cfg.MinBackoff
}
// If the peer failed to start properly, we'll just use the previous
// backoff to compute the subsequent randomized exponential backoff
// duration. This will roughly double on average.
if startTime.IsZero() {
return computeNextBackoff(backoff)
return computeNextBackoff(backoff, s.cfg.MaxBackoff)
}
// The peer succeeded in starting. If the connection didn't last long
@ -2450,7 +2458,7 @@ func (s *server) nextPeerBackoff(pubStr string,
// with this peer.
connDuration := time.Since(startTime)
if connDuration < defaultStableConnDuration {
return computeNextBackoff(backoff)
return computeNextBackoff(backoff, s.cfg.MaxBackoff)
}
// The peer succeed in starting and this was stable peer, so we'll
@ -2458,8 +2466,8 @@ func (s *server) nextPeerBackoff(pubStr string,
// applying randomized exponential backoff. We'll only apply this in the
// case that:
// reb(curBackoff) - connDuration > cfg.MinBackoff
relaxedBackoff := computeNextBackoff(backoff) - connDuration
if relaxedBackoff > cfg.MinBackoff {
relaxedBackoff := computeNextBackoff(backoff, s.cfg.MaxBackoff) - connDuration
if relaxedBackoff > s.cfg.MinBackoff {
return relaxedBackoff
}
@ -2467,7 +2475,7 @@ func (s *server) nextPeerBackoff(pubStr string,
// the stable connection lasted much longer than our previous backoff.
// To reward such good behavior, we'll reconnect after the default
// timeout.
return cfg.MinBackoff
return s.cfg.MinBackoff
}
// shouldDropConnection determines if our local connection to a remote peer
@ -2780,9 +2788,9 @@ func (s *server) peerConnected(conn net.Conn, connReq *connmgr.ConnReq,
// htlcs, an extra block is added to prevent the channel from being
// closed when the htlc is outstanding and a new block comes in.
p, err := newPeer(
conn, connReq, s, peerAddr, inbound, initFeatures,
legacyFeatures, cfg.ChanEnableTimeout,
defaultOutgoingCltvRejectDelta, errBuffer,
s.cfg, conn, connReq, s, peerAddr, inbound, initFeatures,
legacyFeatures, s.cfg.ChanEnableTimeout,
lncfg.DefaultOutgoingCltvRejectDelta, errBuffer,
)
if err != nil {
srvrLog.Errorf("unable to create peer %v", err)
@ -3224,7 +3232,7 @@ func (s *server) ConnectToPeer(addr *lnwire.NetAddress, perm bool) error {
// zero.
s.persistentPeers[targetPub] = true
if _, ok := s.persistentPeersBackoff[targetPub]; !ok {
s.persistentPeersBackoff[targetPub] = cfg.MinBackoff
s.persistentPeersBackoff[targetPub] = s.cfg.MinBackoff
}
s.persistentConnReqs[targetPub] = append(
s.persistentConnReqs[targetPub], connReq,
@ -3256,7 +3264,7 @@ func (s *server) ConnectToPeer(addr *lnwire.NetAddress, perm bool) error {
// notify the caller if the connection attempt has failed. Otherwise, it will be
// closed.
func (s *server) connectToPeer(addr *lnwire.NetAddress, errChan chan<- error) {
conn, err := brontide.Dial(s.identityPriv, addr, cfg.net.Dial)
conn, err := brontide.Dial(s.identityPriv, addr, s.cfg.net.Dial)
if err != nil {
srvrLog.Errorf("Unable to connect to %v: %v", addr, err)
select {
@ -3407,11 +3415,11 @@ func parseHexColor(colorStr string) (color.RGBA, error) {
// backoff using the value of the exiting backoff. The returned duration is
// randomized in either direction by 1/20 to prevent tight loops from
// stabilizing.
func computeNextBackoff(currBackoff time.Duration) time.Duration {
func computeNextBackoff(currBackoff, maxBackoff time.Duration) time.Duration {
// Double the current backoff, truncating if it exceeds our maximum.
nextBackoff := 2 * currBackoff
if nextBackoff > cfg.MaxBackoff {
nextBackoff = cfg.MaxBackoff
if nextBackoff > maxBackoff {
nextBackoff = maxBackoff
}
// Using 1/10 of our duration as a margin, compute a random offset to

View File

@ -114,7 +114,12 @@ func TestTLSAutoRegeneration(t *testing.T) {
// Now let's run getTLSConfig. If it works properly, it should delete
// the cert and create a new one.
_, _, _, err = getTLSConfig(certPath, keyPath, nil, nil, rpcListeners)
cfg := &Config{
TLSCertPath: certPath,
TLSKeyPath: keyPath,
RPCListeners: rpcListeners,
}
_, _, _, err = getTLSConfig(cfg)
if err != nil {
t.Fatalf("couldn't retrieve TLS config")
}

View File

@ -81,7 +81,7 @@ type subRPCServerConfigs struct {
//
// NOTE: This MUST be called before any callers are permitted to execute the
// FetchConfig method.
func (s *subRPCServerConfigs) PopulateDependencies(cc *chainControl,
func (s *subRPCServerConfigs) PopulateDependencies(cfg *Config, cc *chainControl,
networkDir string, macService *macaroons.Service,
atpl *autopilot.Manager,
invoiceRegistry *invoices.InvoiceRegistry,
@ -205,7 +205,7 @@ func (s *subRPCServerConfigs) PopulateDependencies(cc *chainControl,
reflect.ValueOf(nodeSigner),
)
defaultDelta := cfg.Bitcoin.TimeLockDelta
if registeredChains.PrimaryChain() == litecoinChain {
if cfg.registeredChains.PrimaryChain() == litecoinChain {
defaultDelta = cfg.Litecoin.TimeLockDelta
}
subCfgValue.FieldByName("DefaultCLTVExpiry").Set(