chainregistry: add new method to automatically create chainControl

This commit is contained in:
Olaoluwa Osuntokun 2017-05-18 11:49:32 -07:00
parent 42a50224aa
commit 770d6b136f
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2
2 changed files with 205 additions and 120 deletions

@ -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
@ -37,11 +51,190 @@ func (c chainCode) String() string {
// the chains lnd is currently active on.
type chainControl struct {
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{

130
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