From 593ba7c8f06b4aff0b7a19f26c457b7d05182c0f Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 24 May 2017 17:46:37 -0700 Subject: [PATCH] lnd: newChainControlFromConfig can now create light client backed chainControl This commit finishes up the implementation of newChainControlFromConfig in order to properly initiate the members of the chainControl struct when the new light client mode (neutrino). With this lnd is now able to switch over to either mode with a simple configuration change. --- chainregistry.go | 91 ++++++++++++++++++++++++++++-------------------- lnd.go | 5 ++- 2 files changed, 58 insertions(+), 38 deletions(-) diff --git a/chainregistry.go b/chainregistry.go index 0a45f1c2..6f1913c4 100644 --- a/chainregistry.go +++ b/chainregistry.go @@ -13,12 +13,14 @@ import ( "github.com/lightninglabs/neutrino" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs/btcdnotify" + "github.com/lightningnetwork/lnd/chainntnfs/neutrinonotify" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet/btcwallet" "github.com/lightningnetwork/lnd/routing/chainview" "github.com/roasbeef/btcd/chaincfg/chainhash" "github.com/roasbeef/btcrpcclient" + "github.com/roasbeef/btcwallet/chain" "github.com/roasbeef/btcwallet/walletdb" ) @@ -65,8 +67,11 @@ type chainControl struct { wallet *lnwallet.LightningWallet } -// newChainControlFromConfig.... -func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB) (*chainControl, error) { +// newChainControlFromConfig attempts to create a chainControl instance +// according to the parameters in the passed lnd configuration. Currently two +// branches of chainControl instances exist: one backed by a running btcd +// full-node, and the other backed by a running neutrino light client instance. +func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB) (*chainControl, func(), error) { // 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 @@ -88,22 +93,25 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB) (*chainControl } var ( - err error + err error + cleanUp func() ) // If spv mode is active, then we'll be using a distimnct set of // chainControl interfaces that interface directly with the p2p network // of the selected chain. if cfg.SpvMode.Active { - // TODO(roasbeef): create dest for database of chain - // * where to place??? - + // First we'll open the database file for neutrino, creating + // the database if needed. dbName := filepath.Join(cfg.DataDir, "neutrino.db") nodeDatabase, err := walletdb.Create("bdb", dbName) if err != nil { - return nil, err + return nil, nil, err } + // With the database open, we can now create an instance of the + // neutrino light client. We pass in relevant configuration + // parameters required. config := neutrino.Config{ DataDir: cfg.DataDir, Database: nodeDatabase, @@ -111,28 +119,34 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB) (*chainControl AddPeers: cfg.SpvMode.AddPeers, ConnectPeers: cfg.SpvMode.ConnectPeers, } - neutrino.WaitForMoreCFHeaders = time.Second * 1 neutrino.MaxPeers = 8 neutrino.BanDuration = 5 * time.Second svc, err := neutrino.NewChainService(config) if err != nil { - return nil, fmt.Errorf("unable to create neutrino: %v", err) + return nil, nil, fmt.Errorf("unable to create neutrino: %v", err) } svc.Start() - ltndLog.Infof("WAITING!!!!!") - m := make(chan struct{}) - <-m + // Next we'll create the instances of the ChainNotifier and + // FilteredChainView interface which is backed by the neutrino + // light client. + cc.chainNotifier, err = neutrinonotify.New(svc) + if err != nil { + return nil, nil, err + } + cc.chainView, err = chainview.NewCfFilteredChainView(svc) + if err != nil { + return nil, nil, err + } - // TODO(roasbeef): return clean up func in closure to stop spvc - // and rest? - // defer db.Close() - // svc.Stop - - // TODO(roasbeef): need to modify to base things off of - // ChainService - //walletConfig.ChainService = svc + // Finally, we'll set the chain source for btcwallet, and + // create our clean up function which simply closes the + // database. + walletConfig.ChainSource = chain.NewSPVChain(svc) + cleanUp = func() { + defer nodeDatabase.Close() + } } else { // Otherwise, we'll be speaking directly via RPC to a node. // @@ -144,19 +158,19 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB) (*chainControl if homeChainConfig.RawRPCCert != "" { rpcCert, err = hex.DecodeString(homeChainConfig.RawRPCCert) if err != nil { - return nil, err + return nil, nil, err } } else { certFile, err := os.Open(homeChainConfig.RPCCert) if err != nil { - return nil, err + return nil, nil, err } rpcCert, err = ioutil.ReadAll(certFile) if err != nil { - return nil, err + return nil, nil, err } if err := certFile.Close(); err != nil { - return nil, err + return nil, nil, err } } @@ -174,13 +188,6 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB) (*chainControl btcdUser := homeChainConfig.RPCUser btcdPass := homeChainConfig.RPCPass - - // TODO(roasbeef): set chain service for wallet? - walletConfig.RPCHost = btcdHost - walletConfig.RPCUser = homeChainConfig.RPCUser - walletConfig.RPCPass = homeChainConfig.RPCPass - walletConfig.CACert = rpcCert - rpcConfig := &btcrpcclient.ConnConfig{ Host: btcdHost, Endpoint: "ws", @@ -193,7 +200,7 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB) (*chainControl } cc.chainNotifier, err = btcdnotify.New(rpcConfig) if err != nil { - return nil, err + return nil, nil, err } // Finally, we'll create an instance of the default chain view to be @@ -201,14 +208,24 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB) (*chainControl cc.chainView, err = chainview.NewBtcdFilteredChainView(*rpcConfig) if err != nil { srvrLog.Errorf("unable to create chain view: %v", err) - return nil, err + return nil, nil, err } + + // Create a special websockets rpc client for btcd which will be used + // by the wallet for notifications, calls, etc. + chainRpc, err := chain.NewRPCClient(activeNetParams.Params, btcdHost, + btcdUser, btcdPass, rpcCert, false, 20) + if err != nil { + return nil, nil, err + } + + walletConfig.ChainSource = chainRpc } wc, err := btcwallet.New(*walletConfig) if err != nil { fmt.Printf("unable to create wallet controller: %v\n", err) - return nil, err + return nil, nil, err } cc.msgSigner = wc @@ -221,18 +238,18 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB) (*chainControl cc.signer, cc.chainIO, cc.feeEstimator, activeNetParams.Params) if err != nil { fmt.Printf("unable to create wallet: %v\n", err) - return nil, err + return nil, nil, err } if err := wallet.Startup(); err != nil { fmt.Printf("unable to start wallet: %v\n", err) - return nil, err + return nil, nil, err } ltndLog.Info("LightningWallet opened") cc.wallet = wallet - return cc, nil + return cc, cleanUp, nil } var ( diff --git a/lnd.go b/lnd.go index 9380209f..30b6ce92 100644 --- a/lnd.go +++ b/lnd.go @@ -64,11 +64,14 @@ func lndMain() error { // With the information parsed from the configuration, create valid // instances of the paertinent interfaces required to operate the // Lightning Network Daemon. - activeChainControl, err := newChainControlFromConfig(cfg, chanDB) + activeChainControl, chainCleanUp, err := newChainControlFromConfig(cfg, chanDB) if err != nil { fmt.Printf("unable to create chain control: %v\n", err) return err } + if chainCleanUp != nil { + defer chainCleanUp() + } // Finally before we start the server, we'll register the "holy // trinity" of interface for our current "home chain" with the active