Skip to content

Commit

Permalink
Merge pull request #5708 from guggero/remote-signer-extract-wallet
Browse files Browse the repository at this point in the history
refactor: move towards more configurable implementation details
  • Loading branch information
guggero authored Oct 8, 2021
2 parents dd3719d + 0cfe0f4 commit 00af978
Show file tree
Hide file tree
Showing 44 changed files with 4,098 additions and 3,677 deletions.
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 {
// 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

0 comments on commit 00af978

Please sign in to comment.