diff --git a/chainregistry.go b/chainregistry.go index 7a29111f..cca556b2 100644 --- a/chainregistry.go +++ b/chainregistry.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "net" "os" + "path/filepath" "strconv" "strings" "sync" @@ -16,6 +17,7 @@ import ( "github.com/btcsuite/btcutil" "github.com/btcsuite/btcwallet/chain" "github.com/btcsuite/btcwallet/wallet" + "github.com/btcsuite/btcwallet/walletdb" "github.com/lightninglabs/neutrino" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs/bitcoindnotify" @@ -663,3 +665,79 @@ func (c *chainRegistry) NumActiveChains() uint32 { return uint32(len(c.activeChains)) } + +// initNeutrinoBackend inits a new instance of the neutrino light client +// backend given a target chain directory to store the chain state. +func initNeutrinoBackend(chainDir string) (*neutrino.ChainService, func(), error) { + // First we'll open the database file for neutrino, creating the + // database if needed. We append the normalized network name here to + // match the behavior of btcwallet. + dbPath := filepath.Join( + chainDir, + normalizeNetwork(activeNetParams.Name), + ) + + // Ensure that the neutrino db path exists. + if err := os.MkdirAll(dbPath, 0700); err != nil { + return nil, nil, err + } + + dbName := filepath.Join(dbPath, "neutrino.db") + db, err := walletdb.Create("bdb", dbName) + if err != nil { + return nil, nil, fmt.Errorf("unable to create neutrino "+ + "database: %v", 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: dbPath, + Database: db, + ChainParams: *activeNetParams.Params, + AddPeers: cfg.NeutrinoMode.AddPeers, + ConnectPeers: cfg.NeutrinoMode.ConnectPeers, + Dialer: func(addr net.Addr) (net.Conn, error) { + return cfg.net.Dial(addr.Network(), addr.String()) + }, + NameResolver: func(host string) ([]net.IP, error) { + addrs, err := cfg.net.LookupHost(host) + if err != nil { + return nil, err + } + + ips := make([]net.IP, 0, len(addrs)) + for _, strIP := range addrs { + ip := net.ParseIP(strIP) + if ip == nil { + continue + } + + ips = append(ips, ip) + } + + return ips, nil + }, + } + + neutrino.MaxPeers = 8 + neutrino.BanDuration = 5 * time.Second + + neutrinoCS, err := neutrino.NewChainService(config) + if err != nil { + return nil, nil, fmt.Errorf("unable to create neutrino light "+ + "client: %v", err) + } + + cleanUp := func() { + db.Close() + neutrinoCS.Stop() + } + if err := neutrinoCS.Start(); err != nil { + cleanUp() + return nil, nil, err + } + + return neutrinoCS, cleanUp, nil +} diff --git a/lnd.go b/lnd.go index 329acf40..f54820ed 100644 --- a/lnd.go +++ b/lnd.go @@ -35,7 +35,6 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcwallet/wallet" - "github.com/btcsuite/btcwallet/walletdb" proxy "github.com/grpc-ecosystem/grpc-gateway/runtime" flags "github.com/jessevdk/go-flags" "github.com/lightninglabs/neutrino" @@ -198,79 +197,23 @@ func lndMain() error { } proxyOpts := []grpc.DialOption{grpc.WithTransportCredentials(cCreds)} - // Before starting the wallet, we'll create and start our Neutrino light - // client instance, if enabled, in order to allow it to sync while the - // rest of the daemon continues startup. + // Before starting the wallet, we'll create and start our Neutrino + // light client instance, if enabled, in order to allow it to sync + // while the rest of the daemon continues startup. mainChain := cfg.Bitcoin if registeredChains.PrimaryChain() == litecoinChain { mainChain = cfg.Litecoin } var neutrinoCS *neutrino.ChainService if mainChain.Node == "neutrino" { - // First we'll open the database file for neutrino, creating - // the database if needed. We append the normalized network name - // here to match the behavior of btcwallet. - dbPath := filepath.Join( + neutrinoBackend, neutrinoCleanUp, err := initNeutrinoBackend( mainChain.ChainDir, - normalizeNetwork(activeNetParams.Name), ) - - // Ensure that the neutrino db path exists. - if err := os.MkdirAll(dbPath, 0700); err != nil { + defer neutrinoCleanUp() + if err != nil { return err } - - dbName := filepath.Join(dbPath, "neutrino.db") - db, err := walletdb.Create("bdb", dbName) - if err != nil { - return fmt.Errorf("unable to create neutrino "+ - "database: %v", err) - } - defer db.Close() - - // 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: dbPath, - Database: db, - ChainParams: *activeNetParams.Params, - AddPeers: cfg.NeutrinoMode.AddPeers, - ConnectPeers: cfg.NeutrinoMode.ConnectPeers, - Dialer: func(addr net.Addr) (net.Conn, error) { - return cfg.net.Dial(addr.Network(), addr.String()) - }, - NameResolver: func(host string) ([]net.IP, error) { - addrs, err := cfg.net.LookupHost(host) - if err != nil { - return nil, err - } - - ips := make([]net.IP, 0, len(addrs)) - for _, strIP := range addrs { - ip := net.ParseIP(strIP) - if ip == nil { - continue - } - - ips = append(ips, ip) - } - - return ips, nil - }, - } - - neutrino.MaxPeers = 8 - neutrino.BanDuration = 5 * time.Second - - neutrinoCS, err = neutrino.NewChainService(config) - if err != nil { - return fmt.Errorf("unable to create neutrino light "+ - "client: %v", err) - } - - neutrinoCS.Start() - defer neutrinoCS.Stop() + neutrinoCS = neutrinoBackend } var (