Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: move towards more configurable implementation details #5708

Merged
merged 16 commits into from
Oct 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
name: Bitcoind Integration ARM
script:
- bash ./scripts/install_bitcoind.sh
- GOARM=7 GOARCH=arm GOOS=linux make itest-parallel backend=bitcoind tranches=2 parallel=2
- GOARM=7 GOARCH=arm GOOS=linux make itest-parallel backend=bitcoind tranches=3 parallel=3
arch: arm64
services:
- docker
Expand Down
217 changes: 112 additions & 105 deletions chainreg/chainregistry.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/chain"
"github.com/btcsuite/btcwallet/wallet"
"github.com/lightninglabs/neutrino"
"github.com/lightningnetwork/lnd/blockcache"
"github.com/lightningnetwork/lnd/chainntnfs"
Expand All @@ -35,6 +34,7 @@ import (
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/chainview"
"github.com/lightningnetwork/lnd/walletunlocker"
)

// Config houses necessary fields that a chainControl instance needs to
Expand Down Expand Up @@ -77,26 +77,12 @@ type Config struct {
// state.
ChanStateDB *channeldb.ChannelStateDB

// BlockCacheSize is the size (in bytes) of blocks kept in memory.
BlockCacheSize uint64
// BlockCache is the main cache for storing block information.
BlockCache *blockcache.BlockCache

// PrivateWalletPw is the private wallet password to the underlying
// btcwallet instance.
PrivateWalletPw []byte

// PublicWalletPw is the public wallet password to the underlying btcwallet
// instance.
PublicWalletPw []byte

// Birthday specifies the time the wallet was initially created.
Birthday time.Time

// RecoveryWindow specifies the address look-ahead for which to scan when
// restoring a wallet.
RecoveryWindow uint32

// Wallet is a pointer to the backing wallet instance.
Wallet *wallet.Wallet
// WalletUnlockParams are the parameters that were used for unlocking
// the main wallet.
WalletUnlockParams *walletunlocker.WalletUnlockParams

// NeutrinoCS is a pointer to a neutrino ChainService. Must be non-nil if
// using neutrino.
Expand All @@ -113,13 +99,6 @@ type Config struct {
// TCP connections to Bitcoin peers in the event of a pruned block being
// requested.
Dialer chain.Dialer

// LoaderOptions holds functional wallet db loader options.
LoaderOptions []btcwallet.LoaderOption

// CoinSelectionStrategy is the strategy that is used for selecting
// coins when funding a transaction.
CoinSelectionStrategy wallet.CoinSelectionStrategy
}

const (
Expand Down Expand Up @@ -181,53 +160,80 @@ var DefaultLtcChannelConstraints = channeldb.ChannelConstraints{
MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
}

// ChainControl couples the three primary interfaces lnd utilizes for a
// particular chain together. A single ChainControl instance will exist for all
// the chains lnd is currently active on.
type ChainControl struct {
// ChainIO represents an abstraction over a source that can query the blockchain.
ChainIO lnwallet.BlockChainIO
// PartialChainControl contains all the primary interfaces of the chain control
// that can be purely constructed from the global configuration. No wallet
// instance is required for constructing this partial state.
type PartialChainControl struct {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(useless) nit: Not sure about PartialChainControl as a name, but also can't think of a better one (Common/Global..?)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, naming is hard... But I think partial isn't too bad of a name here since we split the initialization into two parts, so it's only complete after the second call.

// Cfg is the configuration that was used to create the partial chain
// control.
Cfg *Config

// HealthCheck is a function which can be used to send a low-cost, fast
// query to the chain backend to ensure we still have access to our
// node.
HealthCheck func() error

// FeeEstimator is used to estimate an optimal fee for transactions important to us.
// FeeEstimator is used to estimate an optimal fee for transactions
// important to us.
FeeEstimator chainfee.Estimator

// ChainNotifier is used to receive blockchain events that we are
// interested in.
ChainNotifier chainntnfs.ChainNotifier

// ChainView is used in the router for maintaining an up-to-date graph.
ChainView chainview.FilteredChainView

// ChainSource is the primary chain interface. This is used to operate
// the wallet and do things such as rescanning, sending transactions,
// notifications for received funds, etc.
ChainSource chain.Interface

// RoutingPolicy is the routing policy we have decided to use.
RoutingPolicy htlcswitch.ForwardingPolicy

// MinHtlcIn is the minimum HTLC we will accept.
MinHtlcIn lnwire.MilliSatoshi

// ChannelConstraints is the set of default constraints that will be
// used for any incoming or outgoing channel reservation requests.
ChannelConstraints channeldb.ChannelConstraints
}

// ChainControl couples the three primary interfaces lnd utilizes for a
// particular chain together. A single ChainControl instance will exist for all
// the chains lnd is currently active on.
type ChainControl struct {
// PartialChainControl is the part of the chain control that was
// initialized purely from the configuration and doesn't contain any
// wallet related elements.
*PartialChainControl

// ChainIO represents an abstraction over a source that can query the
// blockchain.
ChainIO lnwallet.BlockChainIO

// Signer is used to provide signatures over things like transactions.
Signer input.Signer

// KeyRing represents a set of keys that we have the private keys to.
KeyRing keychain.SecretKeyRing

// Wc is an abstraction over some basic wallet commands. This base set of commands
// will be provided to the Wallet *LightningWallet raw pointer below.
// Wc is an abstraction over some basic wallet commands. This base set
// of commands will be provided to the Wallet *LightningWallet raw
// pointer below.
Wc lnwallet.WalletController

// MsgSigner is used to sign arbitrary messages.
MsgSigner lnwallet.MessageSigner

// ChainNotifier is used to receive blockchain events that we are interested in.
ChainNotifier chainntnfs.ChainNotifier

// ChainView is used in the router for maintaining an up-to-date graph.
ChainView chainview.FilteredChainView

// Wallet is our LightningWallet that also contains the abstract Wc above. This wallet
// handles all of the lightning operations.
// Wallet is our LightningWallet that also contains the abstract Wc
// above. This wallet handles all of the lightning operations.
Wallet *lnwallet.LightningWallet

// RoutingPolicy is the routing policy we have decided to use.
RoutingPolicy htlcswitch.ForwardingPolicy

// MinHtlcIn is the minimum HTLC we will accept.
MinHtlcIn lnwire.MilliSatoshi
}

// GenDefaultBtcChannelConstraints generates the default set of channel
// constraints that are to be used when funding a Bitcoin channel.
// GenDefaultBtcConstraints generates the default set of channel constraints
// that are to be used when funding a Bitcoin channel.
func GenDefaultBtcConstraints() channeldb.ChannelConstraints {
// We use the dust limit for the maximally sized witness program with
// a 40-byte data push.
Expand All @@ -239,25 +245,21 @@ func GenDefaultBtcConstraints() channeldb.ChannelConstraints {
}
}

// NewChainControl attempts to create a ChainControl instance according
// to the parameters in the passed configuration. Currently three
// branches of ChainControl instances exist: one backed by a running btcd
// full-node, another backed by a running bitcoind full-node, and the other
// backed by a running neutrino light client instance. When running with a
// neutrino light client instance, `neutrinoCS` must be non-nil.
func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
*ChainControl, func(), error) {

// NewPartialChainControl creates a new partial chain control that contains all
// the parts that can be purely constructed from the passed in global
// configuration and doesn't need any wallet instance yet.
func NewPartialChainControl(cfg *Config) (*PartialChainControl, 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
if cfg.PrimaryChain() == LitecoinChain {
homeChainConfig = cfg.Litecoin
}
log.Infof("Primary chain is set to: %v",
cfg.PrimaryChain())
log.Infof("Primary chain is set to: %v", cfg.PrimaryChain())

cc := &ChainControl{}
cc := &PartialChainControl{
Cfg: cfg,
}

switch cfg.PrimaryChain() {
case BitcoinChain:
Expand Down Expand Up @@ -288,20 +290,7 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
"unknown", cfg.PrimaryChain())
}

walletConfig := &btcwallet.Config{
PrivatePass: cfg.PrivateWalletPw,
PublicPass: cfg.PublicWalletPw,
Birthday: cfg.Birthday,
RecoveryWindow: cfg.RecoveryWindow,
NetParams: cfg.ActiveNetParams.Params,
CoinType: cfg.ActiveNetParams.CoinType,
Wallet: cfg.Wallet,
LoaderOptions: cfg.LoaderOptions,
CoinSelectionStrategy: cfg.CoinSelectionStrategy,
}

var err error

heightHintCacheConfig := chainntnfs.CacheConfig{
QueryDisable: cfg.HeightHintCacheQueryDisable,
}
Expand All @@ -327,10 +316,10 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
// along with the wallet's ChainSource, which are all backed by
// the neutrino light client.
cc.ChainNotifier = neutrinonotify.New(
cfg.NeutrinoCS, hintCache, hintCache, blockCache,
cfg.NeutrinoCS, hintCache, hintCache, cfg.BlockCache,
)
cc.ChainView, err = chainview.NewCfFilteredChainView(
cfg.NeutrinoCS, blockCache,
cfg.NeutrinoCS, cfg.BlockCache,
)
if err != nil {
return nil, nil, err
Expand All @@ -347,13 +336,13 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
cfg.FeeURL = cfg.NeutrinoMode.FeeURL
}

walletConfig.ChainSource = chain.NewNeutrinoClient(
cc.ChainSource = chain.NewNeutrinoClient(
cfg.ActiveNetParams.Params, cfg.NeutrinoCS,
)

// Get our best block as a health check.
cc.HealthCheck = func() error {
_, _, err := walletConfig.ChainSource.GetBestBlock()
_, _, err := cc.ChainSource.GetBestBlock()
return err
}

Expand Down Expand Up @@ -432,12 +421,12 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (

cc.ChainNotifier = bitcoindnotify.New(
bitcoindConn, cfg.ActiveNetParams.Params, hintCache,
hintCache, blockCache,
hintCache, cfg.BlockCache,
)
cc.ChainView = chainview.NewBitcoindFilteredChainView(
bitcoindConn, blockCache,
bitcoindConn, cfg.BlockCache,
)
walletConfig.ChainSource = bitcoindConn.NewBitcoindClient()
cc.ChainSource = bitcoindConn.NewBitcoindClient()

// If we're not in regtest mode, then we'll attempt to use a
// proper fee estimator for testnet.
Expand Down Expand Up @@ -564,7 +553,7 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
}
cc.ChainNotifier, err = btcdnotify.New(
rpcConfig, cfg.ActiveNetParams.Params, hintCache,
hintCache, blockCache,
hintCache, cfg.BlockCache,
)
if err != nil {
return nil, nil, err
Expand All @@ -573,7 +562,7 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
// Finally, we'll create an instance of the default chain view to be
// used within the routing layer.
cc.ChainView, err = chainview.NewBtcdFilteredChainView(
*rpcConfig, blockCache,
*rpcConfig, cfg.BlockCache,
)
if err != nil {
log.Errorf("unable to create chain view: %v", err)
Expand All @@ -588,11 +577,11 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
return nil, nil, err
}

walletConfig.ChainSource = chainRPC
cc.ChainSource = chainRPC

// Use a query for our best block as a health check.
cc.HealthCheck = func() error {
_, _, err := walletConfig.ChainSource.GetBestBlock()
_, _, err := cc.ChainSource.GetBestBlock()
return err
}

Expand Down Expand Up @@ -648,12 +637,6 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
}

ccCleanup := func() {
if cc.Wallet != nil {
if err := cc.Wallet.Shutdown(); err != nil {
log.Errorf("Failed to shutdown wallet: %v", err)
}
}

if cc.FeeEstimator != nil {
if err := cc.FeeEstimator.Stop(); err != nil {
log.Errorf("Failed to stop feeEstimator: %v", err)
Expand All @@ -666,7 +649,37 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
return nil, nil, err
}

wc, err := btcwallet.New(*walletConfig, blockCache)
// Select the default channel constraints for the primary chain.
cc.ChannelConstraints = GenDefaultBtcConstraints()
if cfg.PrimaryChain() == LitecoinChain {
cc.ChannelConstraints = DefaultLtcChannelConstraints
}

return cc, ccCleanup, nil
}

// NewChainControl attempts to create a ChainControl instance according
// to the parameters in the passed configuration. Currently three
// branches of ChainControl instances exist: one backed by a running btcd
// full-node, another backed by a running bitcoind full-node, and the other
// backed by a running neutrino light client instance. When running with a
// neutrino light client instance, `neutrinoCS` must be non-nil.
func NewChainControl(walletConfig *btcwallet.Config,
pcc *PartialChainControl) (*ChainControl, func(), error) {

cc := &ChainControl{
PartialChainControl: pcc,
}

ccCleanup := func() {
if cc.Wallet != nil {
if err := cc.Wallet.Shutdown(); err != nil {
log.Errorf("Failed to shutdown wallet: %v", err)
}
}
}

wc, err := btcwallet.New(*walletConfig, pcc.Cfg.BlockCache)
if err != nil {
fmt.Printf("unable to create wallet controller: %v\n", err)
return nil, ccCleanup, err
Expand All @@ -677,29 +690,23 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
cc.ChainIO = wc
cc.Wc = wc

// Select the default channel constraints for the primary chain.
channelConstraints := GenDefaultBtcConstraints()
if cfg.PrimaryChain() == LitecoinChain {
channelConstraints = DefaultLtcChannelConstraints
}

keyRing := keychain.NewBtcWalletKeyRing(
wc.InternalWallet(), cfg.ActiveNetParams.CoinType,
wc.InternalWallet(), walletConfig.CoinType,
)
cc.KeyRing = keyRing

// Create, and start the lnwallet, which handles the core payment
// channel logic, and exposes control via proxy state machines.
walletCfg := lnwallet.Config{
Database: cfg.ChanStateDB,
Database: pcc.Cfg.ChanStateDB,
Notifier: cc.ChainNotifier,
WalletController: wc,
Signer: cc.Signer,
FeeEstimator: cc.FeeEstimator,
SecretKeyRing: keyRing,
ChainIO: cc.ChainIO,
DefaultConstraints: channelConstraints,
NetParams: *cfg.ActiveNetParams.Params,
DefaultConstraints: cc.ChannelConstraints,
NetParams: *walletConfig.NetParams,
}
lnWallet, err := lnwallet.NewLightningWallet(walletCfg)
if err != nil {
Expand Down
Loading