From 33979b26360ff5e5dd82df250fff7efe8e531c2c Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 1 Aug 2018 16:02:47 -0700 Subject: [PATCH] funding+server: move initialization of funding manager into the server In this commit, we move the initialization of the server into the funding manager itself. We do this as it's no longer the case that _any_ RPC needs to access the funding manager. In the past, this was the only reason that the funding manager was instantiated outside of the server: to be able to respond to queries _before_ the server was started. This change also fixes a bug as atm, the funding manager will try to register for notifications _before_ the ChainNotifier itself has fully started. --- lnd.go | 195 +----------------------------------------------------- server.go | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+), 193 deletions(-) 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.