From 97da7b344498d3f5ec8b4760018d2d2eaf3f634b Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Fri, 13 Mar 2020 16:41:08 +0800 Subject: [PATCH] multi: support config bitcoind fee estimate mode --- chainregistry.go | 12 +++++++---- config.go | 37 ++++++++++++++++++++++++++++++---- docs/INSTALL.md | 4 ++++ lnwallet/chainfee/estimator.go | 18 ++++++++++++++--- sample-lnd.conf | 6 ++++++ 5 files changed, 66 insertions(+), 11 deletions(-) diff --git a/chainregistry.go b/chainregistry.go index 97a0e524..b5df1cf1 100644 --- a/chainregistry.go +++ b/chainregistry.go @@ -343,7 +343,8 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB, HTTPPostMode: true, } if cfg.Bitcoin.Active && !cfg.Bitcoin.RegTest { - ltndLog.Infof("Initializing bitcoind backed fee estimator") + ltndLog.Infof("Initializing bitcoind backed fee estimator in "+ + "%s mode", bitcoindMode.EstimateMode) // Finally, we'll re-initialize the fee estimator, as // if we're using bitcoind as a backend, then we can @@ -351,7 +352,8 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB, // coded value. fallBackFeeRate := chainfee.SatPerKVByte(25 * 1000) cc.feeEstimator, err = chainfee.NewBitcoindEstimator( - *rpcConfig, fallBackFeeRate.FeePerKWeight(), + *rpcConfig, bitcoindMode.EstimateMode, + fallBackFeeRate.FeePerKWeight(), ) if err != nil { return nil, err @@ -360,7 +362,8 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB, return nil, err } } else if cfg.Litecoin.Active && !cfg.Litecoin.RegTest { - ltndLog.Infof("Initializing litecoind backed fee estimator") + ltndLog.Infof("Initializing litecoind backed fee estimator in "+ + "%s mode", bitcoindMode.EstimateMode) // Finally, we'll re-initialize the fee estimator, as // if we're using litecoind as a backend, then we can @@ -368,7 +371,8 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB, // coded value. fallBackFeeRate := chainfee.SatPerKVByte(25 * 1000) cc.feeEstimator, err = chainfee.NewBitcoindEstimator( - *rpcConfig, fallBackFeeRate.FeePerKWeight(), + *rpcConfig, bitcoindMode.EstimateMode, + fallBackFeeRate.FeePerKWeight(), ) if err != nil { return nil, err diff --git a/config.go b/config.go index 8b9d3e0b..040f68e2 100644 --- a/config.go +++ b/config.go @@ -152,6 +152,11 @@ var ( defaultTorSOCKS = net.JoinHostPort("localhost", strconv.Itoa(defaultTorSOCKSPort)) defaultTorDNS = net.JoinHostPort(defaultTorDNSHost, strconv.Itoa(defaultTorDNSPort)) defaultTorControl = net.JoinHostPort("localhost", strconv.Itoa(defaultTorControlPort)) + + // bitcoindEsimateModes defines all the legal values for bitcoind's + // estimatesmartfee RPC call. + defaultBitcoindEstimateMode = "CONSERVATIVE" + bitcoindEstimateModes = [2]string{"ECONOMICAL", defaultBitcoindEstimateMode} ) type chainConfig struct { @@ -200,6 +205,7 @@ type bitcoindConfig struct { RPCPass string `long:"rpcpass" default-mask:"-" description:"Password for RPC connections"` ZMQPubRawBlock string `long:"zmqpubrawblock" description:"The address listening for ZMQ connections to deliver raw block notifications"` ZMQPubRawTx string `long:"zmqpubrawtx" description:"The address listening for ZMQ connections to deliver raw transaction notifications"` + EstimateMode string `long:"estimatemode" description:"The fee estimate mode. Must be either ECONOMICAL or CONSERVATIVE."` } type autoPilotConfig struct { @@ -384,8 +390,9 @@ func loadConfig() (*config, error) { RPCCert: defaultBtcdRPCCertFile, }, BitcoindMode: &bitcoindConfig{ - Dir: defaultBitcoindDir, - RPCHost: defaultRPCHost, + Dir: defaultBitcoindDir, + RPCHost: defaultRPCHost, + EstimateMode: defaultBitcoindEstimateMode, }, Litecoin: &chainConfig{ MinHTLCIn: defaultLitecoinMinHTLCInMSat, @@ -401,8 +408,9 @@ func loadConfig() (*config, error) { RPCCert: defaultLtcdRPCCertFile, }, LitecoindMode: &bitcoindConfig{ - Dir: defaultLitecoindDir, - RPCHost: defaultRPCHost, + Dir: defaultLitecoindDir, + RPCHost: defaultRPCHost, + EstimateMode: defaultBitcoindEstimateMode, }, UnsafeDisconnect: true, MaxPendingChannels: DefaultMaxPendingChannels, @@ -1211,6 +1219,15 @@ func parseRPCParams(cConfig *chainConfig, nodeConfig interface{}, net chainCode, } } + // Ensure that if the estimate mode is set, that it is a legal + // value. + if conf.EstimateMode != "" { + err := checkEstimateMode(conf.EstimateMode) + if err != nil { + return err + } + } + // If all of RPCUser, RPCPass, ZMQBlockHost, and ZMQTxHost are // set, we assume those parameters are good to use. if conf.RPCUser != "" && conf.RPCPass != "" && @@ -1448,6 +1465,18 @@ func checkZMQOptions(zmqBlockHost, zmqTxHost string) error { return nil } +// checkEstimateMode ensures that the provided estimate mode is legal. +func checkEstimateMode(estimateMode string) error { + for _, mode := range bitcoindEstimateModes { + if estimateMode == mode { + return nil + } + } + + return fmt.Errorf("estimatemode must be one of the following: %v", + bitcoindEstimateModes[:]) +} + // normalizeNetwork returns the common name of a network type used to create // file paths. This allows differently versioned networks to use the same path. func normalizeNetwork(network string) string { diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 066fafe7..2a24926c 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -208,6 +208,7 @@ bitcoind: --bitcoind.rpcpass= Password for RPC connections --bitcoind.zmqpubrawblock= The address listening for ZMQ connections to deliver raw block notifications --bitcoind.zmqpubrawtx= The address listening for ZMQ connections to deliver raw transaction notifications + --bitcoind.estimatemode= The fee estimate mode. Must be either "ECONOMICAL" or "CONSERVATIVE". (default: CONSERVATIVE) ``` ## Using btcd @@ -367,6 +368,9 @@ lnd --bitcoin.active --bitcoin.testnet --debuglevel=debug --bitcoin.node=bitcoin the default `bitcoind` settings, having more than one instance of `lnd`, or `lnd` plus any application that consumes the RPC could cause `lnd` to miss crucial updates from the backend. +- The default fee estimate mode in `bitcoind` is CONSERVATIVE. You can set + `bitcoind.estimatemode=ECONOMICAL` to change it into ECONOMICAL. Futhermore, + if you start `bitcoind` in `regtest`, this configuration won't take any effect. # Creating a wallet diff --git a/lnwallet/chainfee/estimator.go b/lnwallet/chainfee/estimator.go index 5f89f122..98c74f61 100644 --- a/lnwallet/chainfee/estimator.go +++ b/lnwallet/chainfee/estimator.go @@ -286,6 +286,11 @@ type BitcoindEstimator struct { // through the network. minFeePerKW SatPerKWeight + // feeMode is the estimate_mode to use when calling "estimatesmartfee". + // It can be either "ECONOMICAL" or "CONSERVATIVE", and it's default + // to "CONSERVATIVE". + feeMode string + bitcoindConn *rpcclient.Client } @@ -294,7 +299,7 @@ type BitcoindEstimator struct { // 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, +func NewBitcoindEstimator(rpcConfig rpcclient.ConnConfig, feeMode string, fallBackFeeRate SatPerKWeight) (*BitcoindEstimator, error) { rpcConfig.DisableConnectOnNew = true @@ -309,6 +314,7 @@ func NewBitcoindEstimator(rpcConfig rpcclient.ConnConfig, return &BitcoindEstimator{ fallbackFeePerKW: fallBackFeeRate, bitcoindConn: chainConn, + feeMode: feeMode, }, nil } @@ -403,9 +409,15 @@ func (b *BitcoindEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight, err if err != nil { return 0, err } - // TODO: Allow selection of economical/conservative modifiers. + + // The mode must be either ECONOMICAL or CONSERVATIVE. + mode, err := json.Marshal(b.feeMode) + if err != nil { + return 0, err + } + resp, err := b.bitcoindConn.RawRequest( - "estimatesmartfee", []json.RawMessage{target}, + "estimatesmartfee", []json.RawMessage{target, mode}, ) if err != nil { return 0, err diff --git a/sample-lnd.conf b/sample-lnd.conf index ee3ce7cf..422def45 100644 --- a/sample-lnd.conf +++ b/sample-lnd.conf @@ -230,6 +230,9 @@ bitcoin.node=btcd ; bitcoind.zmqpubrawblock=tcp://127.0.0.1:28332 ; bitcoind.zmqpubrawtx=tcp://127.0.0.1:28333 +; Fee estimate mode for bitcoind. It must be either "ECONOMICAL" or "CONSERVATIVE". +; If unset, the default value is "CONSERVATIVE". +; bitcoind.estimatemode=CONSERVATIVE [neutrino] @@ -311,6 +314,9 @@ litecoin.node=ltcd ; litecoind.zmqpubrawblock=tcp://127.0.0.1:28332 ; litecoind.zmqpubrawtx=tcp://127.0.0.1:28333 +; Fee estimate mode for litecoind. It must be either "ECONOMICAL" or "CONSERVATIVE". +; If unset, the default value is "CONSERVATIVE". +; litecoind.estimatemode=CONSERVATIVE [autopilot]