diff --git a/lnd.go b/lnd.go index 237e2807..120163af 100644 --- a/lnd.go +++ b/lnd.go @@ -33,6 +33,8 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials" + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcwallet/wallet" proxy "github.com/grpc-ecosystem/grpc-gateway/runtime" flags "github.com/jessevdk/go-flags" "github.com/lightningnetwork/lnd/channeldb" @@ -41,14 +43,9 @@ import ( "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet/btcwallet" - "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/macaroons" "github.com/lightningnetwork/lnd/signal" "github.com/lightningnetwork/lnd/walletunlocker" - "github.com/btcsuite/btcd/btcec" - "github.com/btcsuite/btcd/wire" - "github.com/btcsuite/btcutil" - "github.com/btcsuite/btcwallet/wallet" ) const ( @@ -289,17 +286,6 @@ func lndMain() error { primaryChain := registeredChains.PrimaryChain() registeredChains.RegisterChain(primaryChain, activeChainControl) - // Select the configuration and furnding parameters for Bitcoin or - // Litecoin, depending on the primary registered chain. - chainCfg := cfg.Bitcoin - minRemoteDelay := minBtcRemoteDelay - maxRemoteDelay := maxBtcRemoteDelay - if primaryChain == litecoinChain { - chainCfg = cfg.Litecoin - minRemoteDelay = minLtcRemoteDelay - maxRemoteDelay = maxLtcRemoteDelay - } - // TODO(roasbeef): add rotation idPrivKey, err := activeChainControl.wallet.DerivePrivKey(keychain.KeyDescriptor{ KeyLocator: keychain.KeyLocator{ @@ -328,183 +314,6 @@ func lndMain() error { return err } - // Next, we'll initialize the funding manager itself so it can answer - // queries while the wallet+chain are still syncing. - nodeSigner := newNodeSigner(idPrivKey) - var chanIDSeed [32]byte - if _, err := rand.Read(chanIDSeed[:]); err != nil { - return err - } - fundingMgr, err := newFundingManager(fundingConfig{ - IDKey: idPrivKey.PubKey(), - Wallet: activeChainControl.wallet, - PublishTransaction: activeChainControl.wallet.PublishTransaction, - Notifier: activeChainControl.chainNotifier, - FeeEstimator: activeChainControl.feeEstimator, - SignMessage: func(pubKey *btcec.PublicKey, - msg []byte) (*btcec.Signature, error) { - - if pubKey.IsEqual(idPrivKey.PubKey()) { - return nodeSigner.SignMessage(pubKey, msg) - } - - return activeChainControl.msgSigner.SignMessage( - pubKey, msg, - ) - }, - CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement, error) { - return server.genNodeAnnouncement(true) - }, - SendAnnouncement: func(msg lnwire.Message) error { - errChan := server.authGossiper.ProcessLocalAnnouncement(msg, - idPrivKey.PubKey()) - return <-errChan - }, - NotifyWhenOnline: server.NotifyWhenOnline, - TempChanIDSeed: chanIDSeed, - FindChannel: func(chanID lnwire.ChannelID) (*lnwallet.LightningChannel, error) { - dbChannels, err := chanDB.FetchAllChannels() - if err != nil { - return nil, err - } - - for _, channel := range dbChannels { - if chanID.IsChanPoint(&channel.FundingOutpoint) { - // TODO(roasbeef): populate beacon - return lnwallet.NewLightningChannel( - activeChainControl.signer, - server.witnessBeacon, - channel) - } - } - - return nil, fmt.Errorf("unable to find channel") - }, - DefaultRoutingPolicy: activeChainControl.routingPolicy, - NumRequiredConfs: func(chanAmt btcutil.Amount, - pushAmt lnwire.MilliSatoshi) uint16 { - // For large channels we increase the number - // of confirmations we require for the - // channel to be considered open. As it is - // always the responder that gets to choose - // value, the pushAmt is value being pushed - // to us. This means we have more to lose - // in the case this gets re-orged out, and - // we will require more confirmations before - // we consider it open. - // TODO(halseth): Use Litecoin params in case - // of LTC channels. - - // In case the user has explicitly specified - // a default value for the number of - // confirmations, we use it. - defaultConf := uint16(chainCfg.DefaultNumChanConfs) - if defaultConf != 0 { - return defaultConf - } - - // If not we return a value scaled linearly - // between 3 and 6, depending on channel size. - // TODO(halseth): Use 1 as minimum? - minConf := uint64(3) - maxConf := uint64(6) - maxChannelSize := uint64( - lnwire.NewMSatFromSatoshis(maxFundingAmount)) - stake := lnwire.NewMSatFromSatoshis(chanAmt) + pushAmt - conf := maxConf * uint64(stake) / maxChannelSize - if conf < minConf { - conf = minConf - } - if conf > maxConf { - conf = maxConf - } - return uint16(conf) - }, - RequiredRemoteDelay: func(chanAmt btcutil.Amount) uint16 { - // We scale the remote CSV delay (the time the - // remote have to claim funds in case of a unilateral - // close) linearly from minRemoteDelay blocks - // for small channels, to maxRemoteDelay blocks - // for channels of size maxFundingAmount. - // TODO(halseth): Litecoin parameter for LTC. - - // In case the user has explicitly specified - // a default value for the remote delay, we - // use it. - defaultDelay := uint16(chainCfg.DefaultRemoteDelay) - if defaultDelay > 0 { - return defaultDelay - } - - // If not we scale according to channel size. - delay := uint16(btcutil.Amount(maxRemoteDelay) * - chanAmt / maxFundingAmount) - if delay < minRemoteDelay { - delay = minRemoteDelay - } - if delay > maxRemoteDelay { - delay = maxRemoteDelay - } - return delay - }, - WatchNewChannel: func(channel *channeldb.OpenChannel, - peerKey *btcec.PublicKey) error { - - // First, we'll mark this new peer as a persistent peer - // for re-connection purposes. - server.mu.Lock() - pubStr := string(peerKey.SerializeCompressed()) - server.persistentPeers[pubStr] = struct{}{} - server.mu.Unlock() - - // With that taken care of, we'll send this channel to - // the chain arb so it can react to on-chain events. - return server.chainArb.WatchNewChannel(channel) - }, - ReportShortChanID: func(chanPoint wire.OutPoint) error { - cid := lnwire.NewChanIDFromOutPoint(&chanPoint) - return server.htlcSwitch.UpdateShortChanID(cid) - }, - RequiredRemoteChanReserve: func(chanAmt, - dustLimit btcutil.Amount) btcutil.Amount { - - // By default, we'll require the remote peer to maintain - // at least 1% of the total channel capacity at all - // times. If this value ends up dipping below the dust - // limit, then we'll use the dust limit itself as the - // reserve as required by BOLT #2. - reserve := chanAmt / 100 - if reserve < dustLimit { - reserve = dustLimit - } - - return reserve - }, - RequiredRemoteMaxValue: func(chanAmt btcutil.Amount) lnwire.MilliSatoshi { - // By default, we'll allow the remote peer to fully - // utilize the full bandwidth of the channel, minus our - // required reserve. - reserve := lnwire.NewMSatFromSatoshis(chanAmt / 100) - return lnwire.NewMSatFromSatoshis(chanAmt) - reserve - }, - RequiredRemoteMaxHTLCs: func(chanAmt btcutil.Amount) uint16 { - // By default, we'll permit them to utilize the full - // channel bandwidth. - return uint16(lnwallet.MaxHTLCNumber / 2) - }, - ZombieSweeperInterval: 1 * time.Minute, - ReservationTimeout: 10 * time.Minute, - MinChanSize: btcutil.Amount(cfg.MinChanSize), - }) - if err != nil { - return err - } - if err := fundingMgr.Start(); err != nil { - return err - } - server.fundingMgr = fundingMgr - defer fundingMgr.Stop() - // Check macaroon authentication if macaroons aren't disabled. if macaroonService != nil { serverOpts = append(serverOpts, diff --git a/server.go b/server.go index 7681a1d8..572667ee 100644 --- a/server.go +++ b/server.go @@ -678,6 +678,186 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl, Store: newRetributionStore(chanDB), }) + // Select the configuration and furnding parameters for Bitcoin or + // Litecoin, depending on the primary registered chain. + primaryChain := registeredChains.PrimaryChain() + chainCfg := cfg.Bitcoin + minRemoteDelay := minBtcRemoteDelay + maxRemoteDelay := maxBtcRemoteDelay + if primaryChain == litecoinChain { + chainCfg = cfg.Litecoin + minRemoteDelay = minLtcRemoteDelay + maxRemoteDelay = maxLtcRemoteDelay + } + + nodeSigner := newNodeSigner(privKey) + var chanIDSeed [32]byte + if _, err := rand.Read(chanIDSeed[:]); err != nil { + return nil, err + } + s.fundingMgr, err = newFundingManager(fundingConfig{ + IDKey: privKey.PubKey(), + Wallet: cc.wallet, + PublishTransaction: cc.wallet.PublishTransaction, + Notifier: cc.chainNotifier, + FeeEstimator: cc.feeEstimator, + SignMessage: func(pubKey *btcec.PublicKey, + msg []byte) (*btcec.Signature, error) { + + if pubKey.IsEqual(privKey.PubKey()) { + return nodeSigner.SignMessage(pubKey, msg) + } + + return cc.msgSigner.SignMessage(pubKey, msg) + }, + CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement, error) { + return s.genNodeAnnouncement(true) + }, + SendAnnouncement: func(msg lnwire.Message) error { + errChan := s.authGossiper.ProcessLocalAnnouncement( + msg, privKey.PubKey(), + ) + return <-errChan + }, + NotifyWhenOnline: s.NotifyWhenOnline, + TempChanIDSeed: chanIDSeed, + FindChannel: func(chanID lnwire.ChannelID) (*lnwallet.LightningChannel, error) { + dbChannels, err := chanDB.FetchAllChannels() + if err != nil { + return nil, err + } + + for _, channel := range dbChannels { + if chanID.IsChanPoint(&channel.FundingOutpoint) { + return lnwallet.NewLightningChannel( + cc.signer, s.witnessBeacon, + channel, + ) + } + } + + return nil, fmt.Errorf("unable to find channel") + }, + DefaultRoutingPolicy: cc.routingPolicy, + NumRequiredConfs: func(chanAmt btcutil.Amount, + pushAmt lnwire.MilliSatoshi) uint16 { + // For large channels we increase the number + // of confirmations we require for the + // channel to be considered open. As it is + // always the responder that gets to choose + // value, the pushAmt is value being pushed + // to us. This means we have more to lose + // in the case this gets re-orged out, and + // we will require more confirmations before + // we consider it open. + // TODO(halseth): Use Litecoin params in case + // of LTC channels. + + // In case the user has explicitly specified + // a default value for the number of + // confirmations, we use it. + defaultConf := uint16(chainCfg.DefaultNumChanConfs) + if defaultConf != 0 { + return defaultConf + } + + // If not we return a value scaled linearly + // between 3 and 6, depending on channel size. + // TODO(halseth): Use 1 as minimum? + minConf := uint64(3) + maxConf := uint64(6) + maxChannelSize := uint64( + lnwire.NewMSatFromSatoshis(maxFundingAmount)) + stake := lnwire.NewMSatFromSatoshis(chanAmt) + pushAmt + conf := maxConf * uint64(stake) / maxChannelSize + if conf < minConf { + conf = minConf + } + if conf > maxConf { + conf = maxConf + } + return uint16(conf) + }, + RequiredRemoteDelay: func(chanAmt btcutil.Amount) uint16 { + // We scale the remote CSV delay (the time the + // remote have to claim funds in case of a unilateral + // close) linearly from minRemoteDelay blocks + // for small channels, to maxRemoteDelay blocks + // for channels of size maxFundingAmount. + // TODO(halseth): Litecoin parameter for LTC. + + // In case the user has explicitly specified + // a default value for the remote delay, we + // use it. + defaultDelay := uint16(chainCfg.DefaultRemoteDelay) + if defaultDelay > 0 { + return defaultDelay + } + + // If not we scale according to channel size. + delay := uint16(btcutil.Amount(maxRemoteDelay) * + chanAmt / maxFundingAmount) + if delay < minRemoteDelay { + delay = minRemoteDelay + } + if delay > maxRemoteDelay { + delay = maxRemoteDelay + } + return delay + }, + WatchNewChannel: func(channel *channeldb.OpenChannel, + peerKey *btcec.PublicKey) error { + + // First, we'll mark this new peer as a persistent peer + // for re-connection purposes. + s.mu.Lock() + pubStr := string(peerKey.SerializeCompressed()) + s.persistentPeers[pubStr] = struct{}{} + s.mu.Unlock() + + // With that taken care of, we'll send this channel to + // the chain arb so it can react to on-chain events. + return s.chainArb.WatchNewChannel(channel) + }, + ReportShortChanID: func(chanPoint wire.OutPoint) error { + cid := lnwire.NewChanIDFromOutPoint(&chanPoint) + return s.htlcSwitch.UpdateShortChanID(cid) + }, + RequiredRemoteChanReserve: func(chanAmt, + dustLimit btcutil.Amount) btcutil.Amount { + + // By default, we'll require the remote peer to maintain + // at least 1% of the total channel capacity at all + // times. If this value ends up dipping below the dust + // limit, then we'll use the dust limit itself as the + // reserve as required by BOLT #2. + reserve := chanAmt / 100 + if reserve < dustLimit { + reserve = dustLimit + } + + return reserve + }, + RequiredRemoteMaxValue: func(chanAmt btcutil.Amount) lnwire.MilliSatoshi { + // By default, we'll allow the remote peer to fully + // utilize the full bandwidth of the channel, minus our + // required reserve. + reserve := lnwire.NewMSatFromSatoshis(chanAmt / 100) + return lnwire.NewMSatFromSatoshis(chanAmt) - reserve + }, + RequiredRemoteMaxHTLCs: func(chanAmt btcutil.Amount) uint16 { + // By default, we'll permit them to utilize the full + // channel bandwidth. + return uint16(lnwallet.MaxHTLCNumber / 2) + }, + ZombieSweeperInterval: 1 * time.Minute, + ReservationTimeout: 10 * time.Minute, + MinChanSize: btcutil.Amount(cfg.MinChanSize), + }) + if err != nil { + return nil, err + } + // Create the connection manager which will be responsible for // maintaining persistent outbound connections and also accepting new // incoming connections @@ -752,6 +932,9 @@ func (s *server) Start() error { if err := s.chanRouter.Start(); err != nil { return err } + if err := s.fundingMgr.Start(); err != nil { + return err + } s.connMgr.Start() if err := s.invoices.Start(); err != nil { @@ -820,6 +1003,7 @@ func (s *server) Stop() error { s.connMgr.Stop() s.cc.feeEstimator.Stop() s.invoices.Stop() + s.fundingMgr.Stop() // Disconnect from each active peers to ensure that // peerTerminationWatchers signal completion to each peer.