diff --git a/chainregistry.go b/chainregistry.go index fce16ab3..3997992a 100644 --- a/chainregistry.go +++ b/chainregistry.go @@ -1,11 +1,25 @@ package main import ( + "encoding/hex" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" "sync" + "time" + "github.com/lightninglabs/neutrino" "github.com/lightningnetwork/lnd/chainntnfs" + "github.com/lightningnetwork/lnd/chainntnfs/btcdnotify" + "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/walletdb" ) // chainCode is an enum-like structure for keeping track of the chains currently @@ -36,12 +50,191 @@ func (c chainCode) String() string { // particular chain together. A single chainControl instance will exist for all // the chains lnd is currently active on. type chainControl struct { - chainIO lnwallet.BlockChainIO + chainIO lnwallet.BlockChainIO + + feeEstimator lnwallet.FeeEstimator + + signer lnwallet.Signer + + msgSigner lnwallet.MessageSigner + chainNotifier chainntnfs.ChainNotifier + chainView chainview.FilteredChainView + wallet *lnwallet.LightningWallet } +// newChainControlFromConfig.... +func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB) (*chainControl, 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 + if registeredChains.PrimaryChain() == litecoinChain { + homeChainConfig = cfg.Litecoin + } + ltndLog.Infof("Primary chain is set to: %v", + registeredChains.PrimaryChain()) + + estimator := lnwallet.StaticFeeEstimator{FeeRate: 50} + walletConfig := &btcwallet.Config{ + PrivatePass: []byte("hello"), + DataDir: homeChainConfig.ChainDir, + NetParams: activeNetParams.Params, + } + + cc := &chainControl{ + feeEstimator: estimator, + } + + var ( + err error + ) + + // 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??? + + dbName := filepath.Join(homeChainConfig.ChainDir, "neutrino.db") + nodeDatabase, err := walletdb.Create("bdb", dbName) + if err != nil { + return nil, err + } + + config := neutrino.Config{ + DataDir: homeChainConfig.ChainDir, + Database: nodeDatabase, + ChainParams: *activeNetParams.Params, + 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) + } + svc.Start() + + ltndLog.Infof("WAITING!!!!!") + m := make(chan struct{}) + <-m + + // 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 + } else { + // Otherwise, we'll be speaking directly via RPC to a node. + // + // So first we'll load btcd/ltcd's TLS cert for the RPC + // 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 rpcCert []byte + if homeChainConfig.RawRPCCert != "" { + rpcCert, err = hex.DecodeString(homeChainConfig.RawRPCCert) + if err != nil { + return nil, err + } + } else { + certFile, err := os.Open(homeChainConfig.RPCCert) + if err != nil { + return nil, err + } + rpcCert, err = ioutil.ReadAll(certFile) + if err != nil { + return nil, err + } + if err := certFile.Close(); err != nil { + return nil, err + } + } + + // If the specified host for the btcd/ltcd RPC server already + // has a port specified, then we use that directly. Otherwise, + // we assume the default port according to the selected chain + // parameters. + var btcdHost string + if strings.Contains(homeChainConfig.RPCHost, ":") { + btcdHost = homeChainConfig.RPCHost + } else { + btcdHost = fmt.Sprintf("%v:%v", homeChainConfig.RPCHost, + activeNetParams.rpcPort) + } + + 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", + User: btcdUser, + Pass: btcdPass, + Certificates: rpcCert, + DisableTLS: false, + DisableConnectOnNew: true, + DisableAutoReconnect: false, + } + cc.chainNotifier, err = btcdnotify.New(rpcConfig) + if err != nil { + return nil, err + } + + // Finally, we'll create an instance of the default chain view to be + // used within the routing layer. + cc.chainView, err = chainview.NewBtcdFilteredChainView(*rpcConfig) + if err != nil { + srvrLog.Errorf("unable to create chain view: %v", err) + return nil, err + } + } + + wc, err := btcwallet.New(*walletConfig) + if err != nil { + fmt.Printf("unable to create wallet controller: %v\n", err) + return nil, err + } + + cc.msgSigner = wc + cc.signer = wc + cc.chainIO = wc + + // Create, and start the lnwallet, which handles the core payment + // channel logic, and exposes control via proxy state machines. + wallet, err := lnwallet.NewLightningWallet(chanDB, cc.chainNotifier, wc, + cc.signer, cc.chainIO, cc.feeEstimator, activeNetParams.Params) + if err != nil { + fmt.Printf("unable to create wallet: %v\n", err) + return nil, err + } + if err := wallet.Startup(); err != nil { + fmt.Printf("unable to start wallet: %v\n", err) + return nil, err + } + + ltndLog.Info("LightningWallet opened") + + cc.wallet = wallet + + return cc, nil +} + var ( // bitcoinGenesis is the genesis hash of Bitcoin's testnet chain. bitcoinGenesis = chainhash.Hash([chainhash.HashSize]byte{ diff --git a/lnd.go b/lnd.go index 7a0919a5..9380209f 100644 --- a/lnd.go +++ b/lnd.go @@ -1,16 +1,13 @@ package main import ( - "encoding/hex" "fmt" - "io/ioutil" "net" "net/http" _ "net/http/pprof" "os" "runtime" "strconv" - "strings" "golang.org/x/net/context" @@ -18,14 +15,8 @@ import ( flags "github.com/btcsuite/go-flags" proxy "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/lightningnetwork/lnd/chainntnfs/btcdnotify" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/lnrpc" - "github.com/lightningnetwork/lnd/lnwallet" - "github.com/lightningnetwork/lnd/lnwallet/btcwallet" - "github.com/lightningnetwork/lnd/routing/chainview" - - "github.com/roasbeef/btcrpcclient" ) var ( @@ -70,100 +61,20 @@ func lndMain() error { } defer chanDB.Close() - // 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 { - homeChainConfig = cfg.Litecoin - } - ltndLog.Infof("Primary chain is set to: %v", - registeredChains.PrimaryChain()) - - // Next load btcd's TLS cert for the RPC 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 rpcCert []byte - if homeChainConfig.RawRPCCert != "" { - rpcCert, err = hex.DecodeString(homeChainConfig.RawRPCCert) - if err != nil { - return err - } - } else { - certFile, err := os.Open(homeChainConfig.RPCCert) - if err != nil { - return err - } - rpcCert, err = ioutil.ReadAll(certFile) - if err != nil { - return err - } - if err := certFile.Close(); err != nil { - return err - } - } - - // If the specified host for the btcd RPC server already has a port - // specified, then we use that directly. Otherwise, we assume the - // default port according to the selected chain parameters. - var btcdHost string - if strings.Contains(homeChainConfig.RPCHost, ":") { - btcdHost = homeChainConfig.RPCHost - } else { - btcdHost = fmt.Sprintf("%v:%v", homeChainConfig.RPCHost, activeNetParams.rpcPort) - } - - btcdUser := homeChainConfig.RPCUser - btcdPass := homeChainConfig.RPCPass - - // TODO(roasbeef): parse config here and select chosen notifier instead - rpcConfig := &btcrpcclient.ConnConfig{ - Host: btcdHost, - Endpoint: "ws", - User: btcdUser, - Pass: btcdPass, - Certificates: rpcCert, - DisableTLS: false, - DisableConnectOnNew: true, - DisableAutoReconnect: false, - } - notifier, err := btcdnotify.New(rpcConfig) + // 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) if err != nil { + fmt.Printf("unable to create chain control: %v\n", err) return err } - // TODO(roasbeef): parse config here select chosen WalletController - walletConfig := &btcwallet.Config{ - PrivatePass: []byte("hello"), - DataDir: homeChainConfig.ChainDir, - RPCHost: btcdHost, - RPCUser: homeChainConfig.RPCUser, - RPCPass: homeChainConfig.RPCPass, - CACert: rpcCert, - NetParams: activeNetParams.Params, - } - wc, err := btcwallet.New(*walletConfig) - if err != nil { - fmt.Printf("unable to create wallet controller: %v\n", err) - return err - } - signer := wc - bio := wc - fundingSigner := wc - estimator := lnwallet.StaticFeeEstimator{FeeRate: 50} - - // Create, and start the lnwallet, which handles the core payment - // channel logic, and exposes control via proxy state machines. - wallet, err := lnwallet.NewLightningWallet(chanDB, notifier, wc, signer, - bio, estimator, activeNetParams.Params) - if err != nil { - fmt.Printf("unable to create wallet: %v\n", err) - return err - } - if err := wallet.Startup(); err != nil { - fmt.Printf("unable to start wallet: %v\n", err) - return err - } - ltndLog.Info("LightningWallet opened") + // 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) // Set up the core server which will listen for incoming peer // connections. @@ -171,28 +82,9 @@ func lndMain() error { net.JoinHostPort("", strconv.Itoa(cfg.PeerPort)), } - // 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, &chainControl{ - chainIO: bio, - chainNotifier: notifier, - wallet: wallet, - }) - - // Next, we'll create an instance of the default chain view to be used - // within the routing layer. - chainView, err := chainview.NewBtcdFilteredChainView(*rpcConfig) - if err != nil { - srvrLog.Errorf("unable to create chain view: %v", err) - return err - } - // With all the relevant chains initialized, we can finally start the // server itself. - server, err := newServer(defaultListenAddrs, notifier, bio, - fundingSigner, wallet, estimator, chanDB, chainView) + server, err := newServer(defaultListenAddrs, chanDB, activeChainControl) if err != nil { srvrLog.Errorf("unable to create server: %v\n", err) return err