diff --git a/chainntnfs/btcdnotify/btcd.go b/chainntnfs/btcdnotify/btcd.go index d5750ec2a17..b59ed47d426 100644 --- a/chainntnfs/btcdnotify/btcd.go +++ b/chainntnfs/btcdnotify/btcd.go @@ -60,7 +60,7 @@ type BtcdNotifier struct { active int32 // To be used atomically. stopped int32 // To be used atomically. - chainConn *chain.RPCClient + chainConn *chain.BtcdClient chainParams *chaincfg.Params notificationCancels chan interface{} @@ -135,14 +135,14 @@ func New(config *rpcclient.ConnConfig, chainParams *chaincfg.Params, OnRedeemingTx: notifier.onRedeemingTx, } - rpcCfg := &chain.RPCClientConfig{ + rpcCfg := &chain.BtcdConfig{ ReconnectAttempts: 20, Conn: config, Chain: chainParams, NotificationHandlers: ntfnCallbacks, } - chainRPC, err := chain.NewRPCClientWithConfig(rpcCfg) + chainRPC, err := chain.NewBtcdClientWithConfig(rpcCfg) if err != nil { return nil, err } diff --git a/chainreg/chainregistry.go b/chainreg/chainregistry.go index a9a9ede7049..a4980e63462 100644 --- a/chainreg/chainregistry.go +++ b/chainreg/chainregistry.go @@ -383,18 +383,8 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) { cc.ChainView = chainview.NewBitcoindFilteredChainView( bitcoindConn, cfg.BlockCache, ) - cc.ChainSource = bitcoindConn.NewBitcoindClient() - - // Initialize config to connect to bitcoind RPC. - rpcConfig := &rpcclient.ConnConfig{ - Host: bitcoindHost, - User: bitcoindMode.RPCUser, - Pass: bitcoindMode.RPCPass, - DisableConnectOnNew: true, - DisableAutoReconnect: false, - DisableTLS: true, - HTTPPostMode: true, - } + chainRPC := bitcoindConn.NewBitcoindClient() + cc.ChainSource = chainRPC // If feeurl is not provided, use bitcoind's fee estimator. if cfg.Fee.URL == "" { @@ -406,8 +396,9 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) { // use live fee estimates, rather than a statically // coded value. fallBackFeeRate := chainfee.SatPerKVByte(25 * 1000) + cc.FeeEstimator, err = chainfee.NewBitcoindEstimator( - *rpcConfig, bitcoindMode.EstimateMode, + chainRPC, bitcoindMode.EstimateMode, fallBackFeeRate.FeePerKWeight(), ) if err != nil { @@ -415,25 +406,17 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) { } } - // We need to use some apis that are not exposed by btcwallet, - // for a health check function so we create an ad-hoc bitcoind - // connection. - chainConn, err := rpcclient.New(rpcConfig, nil) - if err != nil { - return nil, nil, err - } - // Before we continue any further, we'll ensure that the // backend understands Taproot. If not, then all the default // features can't be used. - if !backendSupportsTaproot(chainConn) { + if !backendSupportsTaproot(chainRPC) { return nil, nil, fmt.Errorf("node backend does not " + "support taproot") } // The api we will use for our health check depends on the // bitcoind version. - cmd, ver, err := getBitcoindHealthCheckCmd(chainConn) + cmd, ver, err := getBitcoindHealthCheckCmd(chainRPC) if err != nil { return nil, nil, err } @@ -453,7 +436,9 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) { } // Fetch all active zmq notifications from the bitcoind client. - resp, err := chainConn.RawRequest("getzmqnotifications", nil) + resp, err := chainRPC.RawRequest( + "getzmqnotifications", nil, + ) if err != nil { return nil, nil, err } @@ -520,7 +505,7 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) { } cc.HealthCheck = func() error { - _, err := chainConn.RawRequest(cmd, nil) + _, err := chainRPC.RawRequest(cmd, nil) if err != nil { return err } @@ -535,7 +520,7 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) { // Make sure the bitcoind chain backend maintains a // healthy connection to the network by checking the // number of outbound peers. - return checkOutboundPeers(chainConn) + return checkOutboundPeers(chainRPC) } case "btcd": @@ -616,9 +601,12 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) { // Create a special websockets rpc client for btcd which will be // used by the wallet for notifications, calls, etc. - chainRPC, err := chain.NewRPCClient( - cfg.ActiveNetParams.Params, btcdHost, btcdUser, - btcdPass, rpcCert, false, 20, + chainRPC, err := chain.NewBtcdClientWithConfig( + &chain.BtcdConfig{ + Conn: rpcConfig, + Chain: cfg.ActiveNetParams.Params, + ReconnectAttempts: 20, + }, ) if err != nil { return nil, nil, err @@ -630,7 +618,12 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) { restConfCopy := *rpcConfig restConfCopy.Endpoint = "" restConfCopy.HTTPPostMode = true - chainConn, err := rpcclient.New(&restConfCopy, nil) + chainConn, err := chain.NewBtcdClientWithConfig( + &chain.BtcdConfig{ + Conn: &restConfCopy, + Chain: cfg.ActiveNetParams.Params, + }, + ) if err != nil { return nil, nil, err } @@ -658,7 +651,7 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) { // Make sure the btcd chain backend maintains a // healthy connection to the network by checking the // number of outbound peers. - return checkOutboundPeers(chainRPC.Client) + return checkOutboundPeers(chainRPC) } // If feeurl is not provided, use btcd's fee estimator. @@ -671,7 +664,7 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) { // value. fallBackFeeRate := chainfee.SatPerKVByte(25 * 1000) cc.FeeEstimator, err = chainfee.NewBtcdEstimator( - *rpcConfig, fallBackFeeRate.FeePerKWeight(), + chainRPC, fallBackFeeRate.FeePerKWeight(), ) if err != nil { return nil, nil, err @@ -800,7 +793,7 @@ func NewChainControl(walletConfig lnwallet.Config, // command, because it has no locking and is an inexpensive call, which was // added in version 0.15. If we are on an earlier version, we fallback to using // getblockchaininfo. -func getBitcoindHealthCheckCmd(client *rpcclient.Client) (string, int64, error) { +func getBitcoindHealthCheckCmd(client chain.Interface) (string, int64, error) { // Query bitcoind to get our current version. resp, err := client.RawRequest("getnetworkinfo", nil) if err != nil { @@ -896,7 +889,7 @@ var ( // provided RPC client. If the number of outbound peers is below 6, a warning // is logged. This function is intended to ensure that the chain backend // maintains a healthy connection to the network. -func checkOutboundPeers(client *rpcclient.Client) error { +func checkOutboundPeers(client chain.Interface) error { peers, err := client.GetPeerInfo() if err != nil { return err diff --git a/chainreg/no_chain_backend.go b/chainreg/no_chain_backend.go index f68202ea9cd..0f44fb0a190 100644 --- a/chainreg/no_chain_backend.go +++ b/chainreg/no_chain_backend.go @@ -1,6 +1,7 @@ package chainreg import ( + "encoding/json" "errors" "time" @@ -147,6 +148,10 @@ func (n *NoChainSource) Stop() { func (n *NoChainSource) WaitForShutdown() { } +func (n *NoChainSource) GetPeerInfo() ([]btcjson.GetPeerInfoResult, error) { + return nil, errNotImplemented +} + func (n *NoChainSource) GetBestBlock() (*chainhash.Hash, int32, error) { return noChainBackendBestHash, noChainBackendBestHeight, nil } @@ -172,6 +177,12 @@ func (n *NoChainSource) GetBlockHeader(*chainhash.Hash) (*wire.BlockHeader, }, nil } +func (n *NoChainSource) GetBlockChainInfo() (*btcjson.GetBlockChainInfoResult, + error) { + + return nil, errNotImplemented +} + func (n *NoChainSource) IsCurrent() bool { return true } @@ -192,6 +203,12 @@ func (n *NoChainSource) SendRawTransaction(*wire.MsgTx, bool) (*chainhash.Hash, return nil, errNotImplemented } +func (n *NoChainSource) RawRequest(method string, + params []json.RawMessage) (json.RawMessage, error) { + + return nil, errNotImplemented +} + func (n *NoChainSource) Rescan(*chainhash.Hash, []btcutil.Address, map[wire.OutPoint]btcutil.Address) error { diff --git a/chainreg/taproot_check.go b/chainreg/taproot_check.go index dedc717eb3d..e8b14c5edb4 100644 --- a/chainreg/taproot_check.go +++ b/chainreg/taproot_check.go @@ -3,14 +3,14 @@ package chainreg import ( "encoding/json" - "github.com/btcsuite/btcd/rpcclient" + "github.com/btcsuite/btcwallet/chain" ) // backendSupportsTaproot returns true if the backend understands the taproot // soft fork. -func backendSupportsTaproot(rpc *rpcclient.Client) bool { +func backendSupportsTaproot(client chain.Interface) bool { // First, we'll try to access the normal getblockchaininfo call. - chainInfo, err := rpc.GetBlockChainInfo() + chainInfo, err := client.GetBlockChainInfo() if err == nil { // If this call worked, then we'll check that the taproot // deployment is defined. @@ -41,7 +41,7 @@ func backendSupportsTaproot(rpc *rpcclient.Client) bool { // running a newer version of bitcoind that still has the // getblockchaininfo call, but doesn't populate the data, so we'll hit // the new getdeploymentinfo call. - resp, err := rpc.RawRequest("getdeploymentinfo", nil) + resp, err := client.RawRequest("getdeploymentinfo", nil) if err != nil { log.Warnf("unable to make getdeploymentinfo request: %v", err) return false diff --git a/lnmock/chain.go b/lnmock/chain.go index c20a8937331..2d1faae270e 100644 --- a/lnmock/chain.go +++ b/lnmock/chain.go @@ -1,6 +1,8 @@ package lnmock import ( + "encoding/json" + "github.com/btcsuite/btcd/btcjson" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -32,6 +34,28 @@ func (m *MockChain) WaitForShutdown() { m.Called() } +func (m *MockChain) GetPeerInfo() ([]btcjson.GetPeerInfoResult, error) { + args := m.Called() + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).([]btcjson.GetPeerInfoResult), args.Error(1) +} + +func (m *MockChain) GetBlockChainInfo() (*btcjson.GetBlockChainInfoResult, + error) { + + args := m.Called() + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*btcjson.GetBlockChainInfoResult), args.Error(1) +} + func (m *MockChain) GetBestBlock() (*chainhash.Hash, int32, error) { args := m.Called() @@ -114,6 +138,18 @@ func (m *MockChain) SendRawTransaction(tx *wire.MsgTx, allowHighFees bool) ( return args.Get(0).(*chainhash.Hash), args.Error(1) } +func (m *MockChain) RawRequest(method string, + params []json.RawMessage) (json.RawMessage, error) { + + args := m.Called(method, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(json.RawMessage), args.Error(1) +} + func (m *MockChain) Rescan(startHash *chainhash.Hash, addrs []btcutil.Address, outPoints map[wire.OutPoint]btcutil.Address) error { diff --git a/lnwallet/btcwallet/blockchain.go b/lnwallet/btcwallet/blockchain.go index 25b51d5e067..c71e0cb0ec7 100644 --- a/lnwallet/btcwallet/blockchain.go +++ b/lnwallet/btcwallet/blockchain.go @@ -72,7 +72,7 @@ func (b *BtcWallet) GetUtxo(op *wire.OutPoint, pkScript []byte, // Otherwise, the output is assumed to be in the UTXO. return spendReport.Output, nil - case *chain.RPCClient: + case *chain.BtcdClient: txout, err := backend.GetTxOut(&op.Hash, op.Index, false) if err != nil { return nil, err diff --git a/lnwallet/btcwallet/signer_test.go b/lnwallet/btcwallet/signer_test.go index a0e4bba6deb..81bb69bc3a2 100644 --- a/lnwallet/btcwallet/signer_test.go +++ b/lnwallet/btcwallet/signer_test.go @@ -337,7 +337,7 @@ func getChainBackend(t *testing.T, netParams *chaincfg.Params) (chain.Interface, require.NoError(t, err) rpcConfig := miningNode.RPCConfig() - chainClient, err := chain.NewRPCClient( + chainClient, err := chain.NewBtcdClient( netParams, rpcConfig.Host, rpcConfig.User, rpcConfig.Pass, rpcConfig.Certificates, false, 20, ) diff --git a/lnwallet/chainfee/estimator.go b/lnwallet/chainfee/estimator.go index f83cce28512..0c6c45cd618 100644 --- a/lnwallet/chainfee/estimator.go +++ b/lnwallet/chainfee/estimator.go @@ -14,7 +14,7 @@ import ( "time" "github.com/btcsuite/btcd/btcutil" - "github.com/btcsuite/btcd/rpcclient" + "github.com/btcsuite/btcwallet/chain" "github.com/lightningnetwork/lnd/lnutils" ) @@ -153,7 +153,7 @@ type BtcdEstimator struct { // transaction to propagate through the network. minFeeManager *minFeeManager - btcdConn *rpcclient.Client + btcdConn *chain.BtcdClient // filterManager uses our peer's feefilter values to determine a // suitable feerate to use that will allow successful transaction @@ -161,28 +161,21 @@ type BtcdEstimator struct { filterManager *filterManager } -// NewBtcdEstimator creates a new BtcdEstimator given a fully populated -// rpc config that is able to successfully connect and authenticate with the -// btcd node, and also a fall back fee rate. The fallback fee rate is used in -// the occasion that the estimator has insufficient data, or returns zero for a +// NewBtcdEstimator creates a new BtcdEstimator given a fully initialized +// BtcdClient and a fallback fee rate. The BtcdClient should already be +// configured and connected to the btcd node. The fallback fee rate is used in +// in cases where the estimator has insufficient data or returns zero for a // fee estimate. -func NewBtcdEstimator(rpcConfig rpcclient.ConnConfig, +func NewBtcdEstimator(client *chain.BtcdClient, fallBackFeeRate SatPerKWeight) (*BtcdEstimator, error) { - rpcConfig.DisableConnectOnNew = true - rpcConfig.DisableAutoReconnect = false - chainConn, err := rpcclient.New(&rpcConfig, nil) - if err != nil { - return nil, err - } - fetchCb := func() ([]SatPerKWeight, error) { - return fetchBtcdFilters(chainConn) + return fetchBtcdFilters(client) } return &BtcdEstimator{ fallbackFeePerKW: fallBackFeeRate, - btcdConn: chainConn, + btcdConn: client, filterManager: newFilterManager(fetchCb), }, nil } @@ -354,7 +347,7 @@ type BitcoindEstimator struct { // TODO(ziggie): introduce an interface for the client to enhance // testability of the estimator. - bitcoindConn *rpcclient.Client + bitcoindConn *chain.BitcoindClient // filterManager uses our peer's feefilter values to determine a // suitable feerate to use that will allow successful transaction @@ -362,30 +355,22 @@ type BitcoindEstimator struct { filterManager *filterManager } -// NewBitcoindEstimator creates a new BitcoindEstimator given a fully populated -// rpc config that is able to successfully connect and authenticate with the -// bitcoind node, and also a fall back fee rate. The fallback fee rate is used -// in the occasion that the estimator has insufficient data, or returns zero -// for a fee estimate. -func NewBitcoindEstimator(rpcConfig rpcclient.ConnConfig, feeMode string, +// NewBitcoindEstimator creates a new BitcoindEstimator given a fully +// initialized BitcoindClient, a fee mode, and a fallback fee rate. The +// BitcoindClient should already be configured and connected to the bitcoind +// node. The fee mode specifies the method used to estimate fees. The fallback +// fee rate is used in cases where the estimator has insufficient data or +// returns zero for a fee estimate. +func NewBitcoindEstimator(client *chain.BitcoindClient, feeMode string, fallBackFeeRate SatPerKWeight) (*BitcoindEstimator, error) { - rpcConfig.DisableConnectOnNew = true - rpcConfig.DisableAutoReconnect = false - rpcConfig.DisableTLS = true - rpcConfig.HTTPPostMode = true - chainConn, err := rpcclient.New(&rpcConfig, nil) - if err != nil { - return nil, err - } - fetchCb := func() ([]SatPerKWeight, error) { - return fetchBitcoindFilters(chainConn) + return fetchBitcoindFilters(client) } return &BitcoindEstimator{ fallbackFeePerKW: fallBackFeeRate, - bitcoindConn: chainConn, + bitcoindConn: client, feeMode: feeMode, filterManager: newFilterManager(fetchCb), }, nil diff --git a/lnwallet/chainfee/filtermanager.go b/lnwallet/chainfee/filtermanager.go index 2d6fd0a2e15..8c03f24bc12 100644 --- a/lnwallet/chainfee/filtermanager.go +++ b/lnwallet/chainfee/filtermanager.go @@ -8,7 +8,7 @@ import ( "time" "github.com/btcsuite/btcd/btcutil" - "github.com/btcsuite/btcd/rpcclient" + "github.com/btcsuite/btcwallet/chain" "github.com/lightningnetwork/lnd/fn/v2" ) @@ -107,7 +107,7 @@ type bitcoindPeerInfoResp struct { MinFeeFilter float64 `json:"minfeefilter"` } -func fetchBitcoindFilters(client *rpcclient.Client) ([]SatPerKWeight, error) { +func fetchBitcoindFilters(client *chain.BitcoindClient) ([]SatPerKWeight, error) { resp, err := client.RawRequest("getpeerinfo", nil) if err != nil { return nil, err @@ -159,7 +159,7 @@ func fetchBitcoindFilters(client *rpcclient.Client) ([]SatPerKWeight, error) { return outboundPeerFilters, nil } -func fetchBtcdFilters(client *rpcclient.Client) ([]SatPerKWeight, error) { +func fetchBtcdFilters(client *chain.BtcdClient) ([]SatPerKWeight, error) { resp, err := client.GetPeerInfo() if err != nil { return nil, err diff --git a/lnwallet/test/test_interface.go b/lnwallet/test/test_interface.go index 27de51708c9..d91593312b5 100644 --- a/lnwallet/test/test_interface.go +++ b/lnwallet/test/test_interface.go @@ -3267,7 +3267,7 @@ func runTests(t *testing.T, walletDriver *lnwallet.WalletDriver, var aliceClient, bobClient chain.Interface switch backEnd { case "btcd": - aliceClient, err = chain.NewRPCClient( + aliceClient, err = chain.NewBtcdClient( netParams, rpcConfig.Host, rpcConfig.User, rpcConfig.Pass, rpcConfig.Certificates, false, 20, @@ -3275,7 +3275,7 @@ func runTests(t *testing.T, walletDriver *lnwallet.WalletDriver, if err != nil { t.Fatalf("unable to make chain rpc: %v", err) } - bobClient, err = chain.NewRPCClient( + bobClient, err = chain.NewBtcdClient( netParams, rpcConfig.Host, rpcConfig.User, rpcConfig.Pass, rpcConfig.Certificates, false, 20, diff --git a/routing/chainview/btcd.go b/routing/chainview/btcd.go index 2a06fd179fa..1da5ef89558 100644 --- a/routing/chainview/btcd.go +++ b/routing/chainview/btcd.go @@ -12,6 +12,7 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/rpcclient" "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcwallet/chain" "github.com/lightningnetwork/lnd/blockcache" graphdb "github.com/lightningnetwork/lnd/graph/db" ) @@ -29,7 +30,7 @@ type BtcdFilteredChainView struct { bestHeightMtx sync.Mutex bestHeight uint32 - btcdConn *rpcclient.Client + btcdConn *chain.BtcdClient // blockEventQueue is the ordered queue used to keep the order // of connected and disconnected blocks sent to the reader of the @@ -78,11 +79,12 @@ func NewBtcdFilteredChainView(config rpcclient.ConnConfig, OnFilteredBlockDisconnected: chainView.onFilteredBlockDisconnected, } - // Disable connecting to btcd within the rpcclient.New method. We - // defer establishing the connection to our .Start() method. - config.DisableConnectOnNew = true - config.DisableAutoReconnect = false - chainConn, err := rpcclient.New(&config, ntfnCallbacks) + chainConn, err := chain.NewBtcdClientWithConfig( + &chain.BtcdConfig{ + Conn: &config, + NotificationHandlers: ntfnCallbacks, + }, + ) if err != nil { return nil, err }