chainfee: create new chainfee package extracting fees from lnwallet

In this commit, we create a new chainfee package, that houses all fee
related functionality used within the codebase. The creation of this new
package furthers our long-term goal of extracting functionality from the
bloated `lnwallet` package into new distinct packages. Additionally,
this new packages resolves a class of import cycle that could arise if a
new package that was imported by something in `lnwallet` wanted to use
the existing fee related functions in the prior `lnwallet` package.
This commit is contained in:
Olaoluwa Osuntokun committed 2019-10-31 16:41:57 -07:00
1 parent fcf81ed8ff
commit 777ed104a3
47 files changed
+536 -400

No files matched your search

+3 -2
View File
@@ -21,6 +21,7 @@ import (
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
)
const (
@@ -289,7 +290,7 @@ func (b *BtcWallet) IsOurAddress(a btcutil.Address) bool {
//
// This is a part of the WalletController interface.
func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
feeRate lnwallet.SatPerKWeight) (*wire.MsgTx, error) {
feeRate chainfee.SatPerKWeight) (*wire.MsgTx, error) {
// Convert our fee rate from sat/kw to sat/kb since it's required by
// SendOutputs.
@@ -314,7 +315,7 @@ func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
//
// This is a part of the WalletController interface.
func (b *BtcWallet) CreateSimpleTx(outputs []*wire.TxOut,
feeRate lnwallet.SatPerKWeight, dryRun bool) (*txauthor.AuthoredTx, error) {
feeRate chainfee.SatPerKWeight, dryRun bool) (*txauthor.AuthoredTx, error) {
// The fee rate is passed in using units of sat/kw, so we'll convert
// this to sat/KB as the CreateSimpleTx method requires this unit.
@@ -1,4 +1,4 @@
package lnwallet
package chainfee
import (
"encoding/json"
@@ -10,85 +10,41 @@ import (
"sync"
"time"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcutil"
)
const (
// FeePerKwFloor is the lowest fee rate in sat/kw that we should use for
// determining transaction fees.
FeePerKwFloor SatPerKWeight = 253
// maxBlockTarget is the highest number of blocks confirmations that
// a WebAPIFeeEstimator will cache fees for. This number is chosen
// a WebAPIEstimator will cache fees for. This number is chosen
// because it's the highest number of confs bitcoind will return a fee
// estimate for.
maxBlockTarget uint32 = 1009
// minBlockTarget is the lowest number of blocks confirmations that
// a WebAPIFeeEstimator will cache fees for. Requesting an estimate for
// a WebAPIEstimator will cache fees for. Requesting an estimate for
// less than this will result in an error.
minBlockTarget uint32 = 2
// minFeeUpdateTimeout represents the minimum interval in which a
// WebAPIFeeEstimator will request fresh fees from its API.
// WebAPIEstimator will request fresh fees from its API.
minFeeUpdateTimeout = 5 * time.Minute
// maxFeeUpdateTimeout represents the maximum interval in which a
// WebAPIFeeEstimator will request fresh fees from its API.
// WebAPIEstimator will request fresh fees from its API.
maxFeeUpdateTimeout = 20 * time.Minute
)
// SatPerKVByte represents a fee rate in sat/kb.
type SatPerKVByte btcutil.Amount
// FeeForVSize calculates the fee resulting from this fee rate and the given
// vsize in vbytes.
func (s SatPerKVByte) FeeForVSize(vbytes int64) btcutil.Amount {
return btcutil.Amount(s) * btcutil.Amount(vbytes) / 1000
}
// FeePerKWeight converts the current fee rate from sat/kb to sat/kw.
func (s SatPerKVByte) FeePerKWeight() SatPerKWeight {
return SatPerKWeight(s / blockchain.WitnessScaleFactor)
}
// String returns a human-readable string of the fee rate.
func (s SatPerKVByte) String() string {
return fmt.Sprintf("%v sat/kb", int64(s))
}
// SatPerKWeight represents a fee rate in sat/kw.
type SatPerKWeight btcutil.Amount
// FeeForWeight calculates the fee resulting from this fee rate and the given
// weight in weight units (wu).
func (s SatPerKWeight) FeeForWeight(wu int64) btcutil.Amount {
// The resulting fee is rounded down, as specified in BOLT#03.
return btcutil.Amount(s) * btcutil.Amount(wu) / 1000
}
// FeePerKVByte converts the current fee rate from sat/kw to sat/kb.
func (s SatPerKWeight) FeePerKVByte() SatPerKVByte {
return SatPerKVByte(s * blockchain.WitnessScaleFactor)
}
// String returns a human-readable string of the fee rate.
func (s SatPerKWeight) String() string {
return fmt.Sprintf("%v sat/kw", int64(s))
}
// FeeEstimator provides the ability to estimate on-chain transaction fees for
// Estimator provides the ability to estimate on-chain transaction fees for
// various combinations of transaction sizes and desired confirmation time
// (measured by number of blocks).
type FeeEstimator interface {
type Estimator interface {
// EstimateFeePerKW takes in a target for the number of blocks until an
// initial confirmation and returns the estimated fee expressed in
// sat/kw.
EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error)
// Start signals the FeeEstimator to start any processes or goroutines
// Start signals the Estimator to start any processes or goroutines
// it needs to perform its duty.
Start() error
@@ -102,11 +58,11 @@ type FeeEstimator interface {
RelayFeePerKW() SatPerKWeight
}
// StaticFeeEstimator will return a static value for all fee calculation
// requests. It is designed to be replaced by a proper fee calculation
// implementation. The fees are not accessible directly, because changing them
// would not be thread safe.
type StaticFeeEstimator struct {
// StaticEstimator will return a static value for all fee calculation requests.
// It is designed to be replaced by a proper fee calculation implementation.
// The fees are not accessible directly, because changing them would not be
// thread safe.
type StaticEstimator struct {
// feePerKW is the static fee rate in satoshis-per-vbyte that will be
// returned by this fee estimator.
feePerKW SatPerKWeight
@@ -116,11 +72,10 @@ type StaticFeeEstimator struct {
relayFee SatPerKWeight
}
// NewStaticFeeEstimator returns a new static fee estimator instance.
func NewStaticFeeEstimator(feePerKW,
relayFee SatPerKWeight) *StaticFeeEstimator {
// NewStaticEstimator returns a new static fee estimator instance.
func NewStaticEstimator(feePerKW, relayFee SatPerKWeight) *StaticEstimator {
return &StaticFeeEstimator{
return &StaticEstimator{
feePerKW: feePerKW,
relayFee: relayFee,
}
@@ -128,43 +83,43 @@ func NewStaticFeeEstimator(feePerKW,
// EstimateFeePerKW will return a static value for fee calculations.
//
// NOTE: This method is part of the FeeEstimator interface.
func (e StaticFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
// NOTE: This method is part of the Estimator interface.
func (e StaticEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
return e.feePerKW, nil
}
// RelayFeePerKW returns the minimum fee rate required for transactions to be
// relayed.
//
// NOTE: This method is part of the FeeEstimator interface.
func (e StaticFeeEstimator) RelayFeePerKW() SatPerKWeight {
// NOTE: This method is part of the Estimator interface.
func (e StaticEstimator) RelayFeePerKW() SatPerKWeight {
return e.relayFee
}
// Start signals the FeeEstimator to start any processes or goroutines
// Start signals the Estimator to start any processes or goroutines
// it needs to perform its duty.
//
// NOTE: This method is part of the FeeEstimator interface.
func (e StaticFeeEstimator) Start() error {
// NOTE: This method is part of the Estimator interface.
func (e StaticEstimator) Start() error {
return nil
}
// Stop stops any spawned goroutines and cleans up the resources used
// by the fee estimator.
//
// NOTE: This method is part of the FeeEstimator interface.
func (e StaticFeeEstimator) Stop() error {
// NOTE: This method is part of the Estimator interface.
func (e StaticEstimator) Stop() error {
return nil
}
// A compile-time assertion to ensure that StaticFeeEstimator implements the
// FeeEstimator interface.
var _ FeeEstimator = (*StaticFeeEstimator)(nil)
// Estimator interface.
var _ Estimator = (*StaticEstimator)(nil)
// BtcdFeeEstimator is an implementation of the FeeEstimator interface backed
// BtcdEstimator is an implementation of the Estimator interface backed
// by the RPC interface of an active btcd node. This implementation will proxy
// any fee estimation requests to btcd's RPC interface.
type BtcdFeeEstimator struct {
type BtcdEstimator struct {
// fallbackFeePerKW is the fall back fee rate in sat/kw that is returned
// if the fee estimator does not yet have enough data to actually
// produce fee estimates.
@@ -179,13 +134,13 @@ type BtcdFeeEstimator struct {
btcdConn *rpcclient.Client
}
// NewBtcdFeeEstimator creates a new BtcdFeeEstimator given a fully populated
// 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
// fee estimate.
func NewBtcdFeeEstimator(rpcConfig rpcclient.ConnConfig,
fallBackFeeRate SatPerKWeight) (*BtcdFeeEstimator, error) {
func NewBtcdEstimator(rpcConfig rpcclient.ConnConfig,
fallBackFeeRate SatPerKWeight) (*BtcdEstimator, error) {
rpcConfig.DisableConnectOnNew = true
rpcConfig.DisableAutoReconnect = false
@@ -194,17 +149,17 @@ func NewBtcdFeeEstimator(rpcConfig rpcclient.ConnConfig,
return nil, err
}
return &BtcdFeeEstimator{
return &BtcdEstimator{
fallbackFeePerKW: fallBackFeeRate,
btcdConn: chainConn,
}, nil
}
// Start signals the FeeEstimator to start any processes or goroutines
// Start signals the Estimator to start any processes or goroutines
// it needs to perform its duty.
//
// NOTE: This method is part of the FeeEstimator interface.
func (b *BtcdFeeEstimator) Start() error {
// NOTE: This method is part of the Estimator interface.
func (b *BtcdEstimator) Start() error {
if err := b.btcdConn.Connect(20); err != nil {
return err
}
@@ -233,7 +188,7 @@ func (b *BtcdFeeEstimator) Start() error {
b.minFeePerKW = FeePerKwFloor
}
walletLog.Debugf("Using minimum fee rate of %v sat/kw",
log.Debugf("Using minimum fee rate of %v sat/kw",
int64(b.minFeePerKW))
return nil
@@ -242,8 +197,8 @@ func (b *BtcdFeeEstimator) Start() error {
// Stop stops any spawned goroutines and cleans up the resources used
// by the fee estimator.
//
// NOTE: This method is part of the FeeEstimator interface.
func (b *BtcdFeeEstimator) Stop() error {
// NOTE: This method is part of the Estimator interface.
func (b *BtcdEstimator) Stop() error {
b.btcdConn.Shutdown()
return nil
@@ -252,15 +207,15 @@ func (b *BtcdFeeEstimator) Stop() error {
// EstimateFeePerKW takes in a target for the number of blocks until an initial
// confirmation and returns the estimated fee expressed in sat/kw.
//
// NOTE: This method is part of the FeeEstimator interface.
func (b *BtcdFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
// NOTE: This method is part of the Estimator interface.
func (b *BtcdEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
feeEstimate, err := b.fetchEstimate(numBlocks)
switch {
// If the estimator doesn't have enough data, or returns an error, then
// to return a proper value, then we'll return the default fall back
// fee rate.
case err != nil:
walletLog.Errorf("unable to query estimator: %v", err)
log.Errorf("unable to query estimator: %v", err)
fallthrough
case feeEstimate == 0:
@@ -273,14 +228,14 @@ func (b *BtcdFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, er
// RelayFeePerKW returns the minimum fee rate required for transactions to be
// relayed.
//
// NOTE: This method is part of the FeeEstimator interface.
func (b *BtcdFeeEstimator) RelayFeePerKW() SatPerKWeight {
// NOTE: This method is part of the Estimator interface.
func (b *BtcdEstimator) RelayFeePerKW() SatPerKWeight {
return b.minFeePerKW
}
// fetchEstimate returns a fee estimate for a transaction to be confirmed in
// confTarget blocks. The estimate is returned in sat/kw.
func (b *BtcdFeeEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight, error) {
func (b *BtcdEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight, error) {
// First, we'll fetch the estimate for our confirmation target.
btcPerKB, err := b.btcdConn.EstimateFee(int64(confTarget))
if err != nil {
@@ -300,26 +255,26 @@ func (b *BtcdFeeEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight, erro
// Finally, we'll enforce our fee floor.
if satPerKw < b.minFeePerKW {
walletLog.Debugf("Estimated fee rate of %v sat/kw is too low, "+
log.Debugf("Estimated fee rate of %v sat/kw is too low, "+
"using fee floor of %v sat/kw instead", satPerKw,
b.minFeePerKW)
satPerKw = b.minFeePerKW
}
walletLog.Debugf("Returning %v sat/kw for conf target of %v",
log.Debugf("Returning %v sat/kw for conf target of %v",
int64(satPerKw), confTarget)
return satPerKw, nil
}
// A compile-time assertion to ensure that BtcdFeeEstimator implements the
// FeeEstimator interface.
var _ FeeEstimator = (*BtcdFeeEstimator)(nil)
// A compile-time assertion to ensure that BtcdEstimator implements the
// Estimator interface.
var _ Estimator = (*BtcdEstimator)(nil)
// BitcoindFeeEstimator is an implementation of the FeeEstimator interface
// backed by the RPC interface of an active bitcoind node. This implementation
// will proxy any fee estimation requests to bitcoind's RPC interface.
type BitcoindFeeEstimator struct {
// BitcoindEstimator is an implementation of the Estimator interface backed by
// the RPC interface of an active bitcoind node. This implementation will proxy
// any fee estimation requests to bitcoind's RPC interface.
type BitcoindEstimator struct {
// fallbackFeePerKW is the fallback fee rate in sat/kw that is returned
// if the fee estimator does not yet have enough data to actually
// produce fee estimates.
@@ -334,13 +289,13 @@ type BitcoindFeeEstimator struct {
bitcoindConn *rpcclient.Client
}
// NewBitcoindFeeEstimator creates a new BitcoindFeeEstimator 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 NewBitcoindFeeEstimator(rpcConfig rpcclient.ConnConfig,
fallBackFeeRate SatPerKWeight) (*BitcoindFeeEstimator, error) {
// 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,
fallBackFeeRate SatPerKWeight) (*BitcoindEstimator, error) {
rpcConfig.DisableConnectOnNew = true
rpcConfig.DisableAutoReconnect = false
@@ -351,17 +306,17 @@ func NewBitcoindFeeEstimator(rpcConfig rpcclient.ConnConfig,
return nil, err
}
return &BitcoindFeeEstimator{
return &BitcoindEstimator{
fallbackFeePerKW: fallBackFeeRate,
bitcoindConn: chainConn,
}, nil
}
// Start signals the FeeEstimator to start any processes or goroutines
// Start signals the Estimator to start any processes or goroutines
// it needs to perform its duty.
//
// NOTE: This method is part of the FeeEstimator interface.
func (b *BitcoindFeeEstimator) Start() error {
// NOTE: This method is part of the Estimator interface.
func (b *BitcoindEstimator) Start() error {
// Once the connection to the backend node has been established, we'll
// query it for its minimum relay fee. Since the `getinfo` RPC has been
// deprecated for `bitcoind`, we'll need to send a `getnetworkinfo`
@@ -396,7 +351,7 @@ func (b *BitcoindFeeEstimator) Start() error {
b.minFeePerKW = FeePerKwFloor
}
walletLog.Debugf("Using minimum fee rate of %v sat/kw",
log.Debugf("Using minimum fee rate of %v sat/kw",
int64(b.minFeePerKW))
return nil
@@ -405,23 +360,23 @@ func (b *BitcoindFeeEstimator) Start() error {
// Stop stops any spawned goroutines and cleans up the resources used
// by the fee estimator.
//
// NOTE: This method is part of the FeeEstimator interface.
func (b *BitcoindFeeEstimator) Stop() error {
// NOTE: This method is part of the Estimator interface.
func (b *BitcoindEstimator) Stop() error {
return nil
}
// EstimateFeePerKW takes in a target for the number of blocks until an initial
// confirmation and returns the estimated fee expressed in sat/kw.
//
// NOTE: This method is part of the FeeEstimator interface.
func (b *BitcoindFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
// NOTE: This method is part of the Estimator interface.
func (b *BitcoindEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
feeEstimate, err := b.fetchEstimate(numBlocks)
switch {
// If the estimator doesn't have enough data, or returns an error, then
// to return a proper value, then we'll return the default fall back
// fee rate.
case err != nil:
walletLog.Errorf("unable to query estimator: %v", err)
log.Errorf("unable to query estimator: %v", err)
fallthrough
case feeEstimate == 0:
@@ -434,14 +389,14 @@ func (b *BitcoindFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight
// RelayFeePerKW returns the minimum fee rate required for transactions to be
// relayed.
//
// NOTE: This method is part of the FeeEstimator interface.
func (b *BitcoindFeeEstimator) RelayFeePerKW() SatPerKWeight {
// NOTE: This method is part of the Estimator interface.
func (b *BitcoindEstimator) RelayFeePerKW() SatPerKWeight {
return b.minFeePerKW
}
// fetchEstimate returns a fee estimate for a transaction to be confirmed in
// confTarget blocks. The estimate is returned in sat/kw.
func (b *BitcoindFeeEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight, error) {
func (b *BitcoindEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight, error) {
// First, we'll send an "estimatesmartfee" command as a raw request,
// since it isn't supported by btcd but is available in bitcoind.
target, err := json.Marshal(uint64(confTarget))
@@ -478,26 +433,26 @@ func (b *BitcoindFeeEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight,
// Finally, we'll enforce our fee floor.
if satPerKw < b.minFeePerKW {
walletLog.Debugf("Estimated fee rate of %v sat/kw is too low, "+
log.Debugf("Estimated fee rate of %v sat/kw is too low, "+
"using fee floor of %v sat/kw instead", satPerKw,
b.minFeePerKW)
satPerKw = b.minFeePerKW
}
walletLog.Debugf("Returning %v sat/kw for conf target of %v",
log.Debugf("Returning %v sat/kw for conf target of %v",
int64(satPerKw), confTarget)
return satPerKw, nil
}
// A compile-time assertion to ensure that BitcoindFeeEstimator implements the
// FeeEstimator interface.
var _ FeeEstimator = (*BitcoindFeeEstimator)(nil)
// A compile-time assertion to ensure that BitcoindEstimator implements the
// Estimator interface.
var _ Estimator = (*BitcoindEstimator)(nil)
// WebAPIFeeSource is an interface allows the WebAPIFeeEstimator to query an
// WebAPIFeeSource is an interface allows the WebAPIEstimator to query an
// arbitrary HTTP-based fee estimator. Each new set/network will gain an
// implementation of this interface in order to allow the WebAPIFeeEstimator to
// implementation of this interface in order to allow the WebAPIEstimator to
// be fully generic in its logic.
type WebAPIFeeSource interface {
// GenQueryURL generates the full query URL. The value returned by this
@@ -554,9 +509,9 @@ func (s SparseConfFeeSource) ParseResponse(r io.Reader) (map[uint32]uint32, erro
// WebAPIFeeSource interface.
var _ WebAPIFeeSource = (*SparseConfFeeSource)(nil)
// WebAPIFeeEstimator is an implementation of the FeeEstimator interface that
// WebAPIEstimator is an implementation of the Estimator interface that
// queries an HTTP-based fee estimation from an existing web API.
type WebAPIFeeEstimator struct {
type WebAPIEstimator struct {
started sync.Once
stopped sync.Once
@@ -581,12 +536,12 @@ type WebAPIFeeEstimator struct {
wg sync.WaitGroup
}
// NewWebAPIFeeEstimator creates a new WebAPIFeeEstimator from a given URL and a
// NewWebAPIEstimator creates a new WebAPIEstimator from a given URL and a
// fallback default fee. The fees are updated whenever a new block is mined.
func NewWebAPIFeeEstimator(
api WebAPIFeeSource, defaultFee SatPerKWeight) *WebAPIFeeEstimator {
func NewWebAPIEstimator(
api WebAPIFeeSource, defaultFee SatPerKWeight) *WebAPIEstimator {
return &WebAPIFeeEstimator{
return &WebAPIEstimator{
apiSource: api,
feeByBlockTarget: make(map[uint32]uint32),
defaultFeePerKw: defaultFee,
@@ -597,8 +552,8 @@ func NewWebAPIFeeEstimator(
// EstimateFeePerKW takes in a target for the number of blocks until an initial
// confirmation and returns the estimated fee expressed in sat/kw.
//
// NOTE: This method is part of the FeeEstimator interface.
func (w *WebAPIFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
// NOTE: This method is part of the Estimator interface.
func (w *WebAPIEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
if numBlocks > maxBlockTarget {
numBlocks = maxBlockTarget
} else if numBlocks < minBlockTarget {
@@ -618,20 +573,20 @@ func (w *WebAPIFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight,
satPerKw = FeePerKwFloor
}
walletLog.Debugf("Web API returning %v sat/kw for conf target of %v",
log.Debugf("Web API returning %v sat/kw for conf target of %v",
int64(satPerKw), numBlocks)
return satPerKw, nil
}
// Start signals the FeeEstimator to start any processes or goroutines it needs
// Start signals the Estimator to start any processes or goroutines it needs
// to perform its duty.
//
// NOTE: This method is part of the FeeEstimator interface.
func (w *WebAPIFeeEstimator) Start() error {
// NOTE: This method is part of the Estimator interface.
func (w *WebAPIEstimator) Start() error {
var err error
w.started.Do(func() {
walletLog.Infof("Starting web API fee estimator")
log.Infof("Starting web API fee estimator")
w.updateFeeTicker = time.NewTicker(w.randomFeeUpdateTimeout())
w.updateFeeEstimates()
@@ -646,10 +601,10 @@ func (w *WebAPIFeeEstimator) Start() error {
// Stop stops any spawned goroutines and cleans up the resources used by the
// fee estimator.
//
// NOTE: This method is part of the FeeEstimator interface.
func (w *WebAPIFeeEstimator) Stop() error {
// NOTE: This method is part of the Estimator interface.
func (w *WebAPIEstimator) Stop() error {
w.stopped.Do(func() {
walletLog.Infof("Stopping web API fee estimator")
log.Infof("Stopping web API fee estimator")
w.updateFeeTicker.Stop()
@@ -662,15 +617,15 @@ func (w *WebAPIFeeEstimator) Stop() error {
// RelayFeePerKW returns the minimum fee rate required for transactions to be
// relayed.
//
// NOTE: This method is part of the FeeEstimator interface.
func (w *WebAPIFeeEstimator) RelayFeePerKW() SatPerKWeight {
// NOTE: This method is part of the Estimator interface.
func (w *WebAPIEstimator) RelayFeePerKW() SatPerKWeight {
return FeePerKwFloor
}
// randomFeeUpdateTimeout returns a random timeout between minFeeUpdateTimeout
// and maxFeeUpdateTimeout that will be used to determine how often the Estimator
// should retrieve fresh fees from its API.
func (w *WebAPIFeeEstimator) randomFeeUpdateTimeout() time.Duration {
func (w *WebAPIEstimator) randomFeeUpdateTimeout() time.Duration {
lower := int64(minFeeUpdateTimeout)
upper := int64(maxFeeUpdateTimeout)
return time.Duration(prand.Int63n(upper-lower) + lower)
@@ -679,7 +634,7 @@ func (w *WebAPIFeeEstimator) randomFeeUpdateTimeout() time.Duration {
// getCachedFee takes in a target for the number of blocks until an initial
// confirmation and returns an estimated fee (if one was returned by the API). If
// the fee was not previously cached, we cache it here.
func (w *WebAPIFeeEstimator) getCachedFee(numBlocks uint32) (uint32, error) {
func (w *WebAPIEstimator) getCachedFee(numBlocks uint32) (uint32, error) {
w.feesMtx.Lock()
defer w.feesMtx.Unlock()
@@ -704,7 +659,7 @@ func (w *WebAPIFeeEstimator) getCachedFee(numBlocks uint32) (uint32, error) {
}
// updateFeeEstimates re-queries the API for fresh fees and caches them.
func (w *WebAPIFeeEstimator) updateFeeEstimates() {
func (w *WebAPIEstimator) updateFeeEstimates() {
// Rather than use the default http.Client, we'll make a custom one
// which will allow us to control how long we'll wait to read the
// response from the service. This way, if the service is down or
@@ -725,7 +680,7 @@ func (w *WebAPIFeeEstimator) updateFeeEstimates() {
targetURL := w.apiSource.GenQueryURL()
resp, err := netClient.Get(targetURL)
if err != nil {
walletLog.Errorf("unable to query web api for fee response: %v",
log.Errorf("unable to query web api for fee response: %v",
err)
return
}
@@ -735,7 +690,7 @@ func (w *WebAPIFeeEstimator) updateFeeEstimates() {
// to parse out the body to obtain our final result.
feesByBlockTarget, err := w.apiSource.ParseResponse(resp.Body)
if err != nil {
walletLog.Errorf("unable to query web api for fee response: %v",
log.Errorf("unable to query web api for fee response: %v",
err)
return
}
@@ -746,7 +701,7 @@ func (w *WebAPIFeeEstimator) updateFeeEstimates() {
}
// feeUpdateManager updates the fee estimates whenever a new block comes in.
func (w *WebAPIFeeEstimator) feeUpdateManager() {
func (w *WebAPIEstimator) feeUpdateManager() {
defer w.wg.Done()
for {
@@ -759,6 +714,6 @@ func (w *WebAPIFeeEstimator) feeUpdateManager() {
}
}
// A compile-time assertion to ensure that WebAPIFeeEstimator implements the
// FeeEstimator interface.
var _ FeeEstimator = (*WebAPIFeeEstimator)(nil)
// A compile-time assertion to ensure that WebAPIEstimator implements the
// Estimator interface.
var _ Estimator = (*WebAPIEstimator)(nil)
@@ -1,4 +1,4 @@
package lnwallet_test
package chainfee
import (
"bytes"
@@ -9,8 +9,6 @@ import (
"testing"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/lnwallet"
)
type mockSparseConfFeeSource struct {
@@ -38,9 +36,9 @@ func TestFeeRateTypes(t *testing.T) {
const weight = vsize * 4
// Test the conversion from sat/kw to sat/kb.
for feePerKw := lnwallet.SatPerKWeight(250); feePerKw < 10000; feePerKw += 50 {
for feePerKw := SatPerKWeight(250); feePerKw < 10000; feePerKw += 50 {
feePerKB := feePerKw.FeePerKVByte()
if feePerKB != lnwallet.SatPerKVByte(feePerKw*4) {
if feePerKB != SatPerKVByte(feePerKw*4) {
t.Fatalf("expected %d sat/kb, got %d sat/kb when "+
"converting from %d sat/kw", feePerKw*4,
feePerKB, feePerKw)
@@ -62,9 +60,9 @@ func TestFeeRateTypes(t *testing.T) {
}
// Test the conversion from sat/kb to sat/kw.
for feePerKB := lnwallet.SatPerKVByte(1000); feePerKB < 40000; feePerKB += 1000 {
for feePerKB := SatPerKVByte(1000); feePerKB < 40000; feePerKB += 1000 {
feePerKw := feePerKB.FeePerKWeight()
if feePerKw != lnwallet.SatPerKWeight(feePerKB/4) {
if feePerKw != SatPerKWeight(feePerKB/4) {
t.Fatalf("expected %d sat/kw, got %d sat/kw when "+
"converting from %d sat/kb", feePerKB/4,
feePerKw, feePerKB)
@@ -91,9 +89,9 @@ func TestFeeRateTypes(t *testing.T) {
func TestStaticFeeEstimator(t *testing.T) {
t.Parallel()
const feePerKw = lnwallet.FeePerKwFloor
const feePerKw = FeePerKwFloor
feeEstimator := lnwallet.NewStaticFeeEstimator(feePerKw, 0)
feeEstimator := NewStaticEstimator(feePerKw, 0)
if err := feeEstimator.Start(); err != nil {
t.Fatalf("unable to start fee estimator: %v", err)
}
@@ -116,7 +114,7 @@ func TestSparseConfFeeSource(t *testing.T) {
// Test that GenQueryURL returns the URL as is.
url := "test"
feeSource := lnwallet.SparseConfFeeSource{URL: url}
feeSource := SparseConfFeeSource{URL: url}
queryURL := feeSource.GenQueryURL()
if queryURL != url {
t.Fatalf("expected query URL of %v, got %v", url, queryURL)
@@ -166,7 +164,7 @@ func TestSparseConfFeeSource(t *testing.T) {
func TestWebAPIFeeEstimator(t *testing.T) {
t.Parallel()
feeFloor := uint32(lnwallet.FeePerKwFloor.FeePerKVByte())
feeFloor := uint32(FeePerKwFloor.FeePerKVByte())
testCases := []struct {
name string
target uint32
@@ -194,7 +192,7 @@ func TestWebAPIFeeEstimator(t *testing.T) {
fees: testFees,
}
estimator := lnwallet.NewWebAPIFeeEstimator(feeSource, 10)
estimator := NewWebAPIEstimator(feeSource, 10)
// Test that requesting a fee when no fees have been cached fails.
_, err := estimator.EstimateFeePerKW(5)
@@ -210,6 +208,7 @@ func TestWebAPIFeeEstimator(t *testing.T) {
defer estimator.Stop()
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
est, err := estimator.EstimateFeePerKW(tc.target)
if tc.err != "" {
@@ -220,7 +219,7 @@ func TestWebAPIFeeEstimator(t *testing.T) {
"fail, instead got: %v", err)
}
} else {
exp := lnwallet.SatPerKVByte(tc.est).FeePerKWeight()
exp := SatPerKVByte(tc.est).FeePerKWeight()
if err != nil {
t.Fatalf("unable to estimate fee for "+
"%v block target, got: %v",
+29
View File
@@ -0,0 +1,29 @@
package chainfee
import (
"github.com/btcsuite/btclog"
"github.com/lightningnetwork/lnd/build"
)
// log is a logger that is initialized with no output filters. This means the
// package will not perform any logging by default until the caller requests
// it.
var log btclog.Logger
// The default amount of logging is none.
func init() {
UseLogger(build.NewSubLogger("CFEE", nil))
}
// DisableLog disables all library log output. Logging output is disabled by
// default until UseLogger is called.
func DisableLog() {
UseLogger(btclog.Disabled)
}
// UseLogger uses a specified Logger to output package logging info. This
// should be used in preference to SetLogWriter if the caller is also using
// btclog.
func UseLogger(logger btclog.Logger) {
log = logger
}
+53
View File
@@ -0,0 +1,53 @@
package chainfee
import (
"fmt"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcutil"
)
const (
// FeePerKwFloor is the lowest fee rate in sat/kw that we should use for
// determining transaction fees.
FeePerKwFloor SatPerKWeight = 253
)
// SatPerKVByte represents a fee rate in sat/kb.
type SatPerKVByte btcutil.Amount
// FeeForVSize calculates the fee resulting from this fee rate and the given
// vsize in vbytes.
func (s SatPerKVByte) FeeForVSize(vbytes int64) btcutil.Amount {
return btcutil.Amount(s) * btcutil.Amount(vbytes) / 1000
}
// FeePerKWeight converts the current fee rate from sat/kb to sat/kw.
func (s SatPerKVByte) FeePerKWeight() SatPerKWeight {
return SatPerKWeight(s / blockchain.WitnessScaleFactor)
}
// String returns a human-readable string of the fee rate.
func (s SatPerKVByte) String() string {
return fmt.Sprintf("%v sat/kb", int64(s))
}
// SatPerKWeight represents a fee rate in sat/kw.
type SatPerKWeight btcutil.Amount
// FeeForWeight calculates the fee resulting from this fee rate and the given
// weight in weight units (wu).
func (s SatPerKWeight) FeeForWeight(wu int64) btcutil.Amount {
// The resulting fee is rounded down, as specified in BOLT#03.
return btcutil.Amount(s) * btcutil.Amount(wu) / 1000
}
// FeePerKVByte converts the current fee rate from sat/kw to sat/kb.
func (s SatPerKWeight) FeePerKVByte() SatPerKVByte {
return SatPerKVByte(s * blockchain.WitnessScaleFactor)
}
// String returns a human-readable string of the fee rate.
func (s SatPerKWeight) String() string {
return fmt.Sprintf("%v sat/kw", int64(s))
}
+39 -33
View File
@@ -22,6 +22,7 @@ import (
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwire"
)
@@ -512,7 +513,7 @@ type commitment struct {
// feePerKw is the fee per kw used to calculate this commitment
// transaction's fee.
feePerKw SatPerKWeight
feePerKw chainfee.SatPerKWeight
// dustLimit is the limit on the commitment transaction such that no
// output values should be below this amount.
@@ -759,7 +760,7 @@ func (c *commitment) toDiskCommit(ourCommit bool) *channeldb.ChannelCommitment {
// commitment struct and updateLog. This function is used when we need to
// restore commitment state written do disk back into memory once we need to
// restart a channel session.
func (lc *LightningChannel) diskHtlcToPayDesc(feeRate SatPerKWeight,
func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight,
commitHeight uint64, htlc *channeldb.HTLC, localCommitKeys,
remoteCommitKeys *CommitmentKeyRing) (PaymentDescriptor, error) {
@@ -824,7 +825,7 @@ func (lc *LightningChannel) diskHtlcToPayDesc(feeRate SatPerKWeight,
// these payment descriptors can be re-inserted into the in-memory updateLog
// for each side.
func (lc *LightningChannel) extractPayDescs(commitHeight uint64,
feeRate SatPerKWeight, htlcs []channeldb.HTLC, localCommitKeys,
feeRate chainfee.SatPerKWeight, htlcs []channeldb.HTLC, localCommitKeys,
remoteCommitKeys *CommitmentKeyRing) ([]PaymentDescriptor, []PaymentDescriptor, error) {
var (
@@ -894,7 +895,8 @@ func (lc *LightningChannel) diskCommitToMemCommit(isLocal bool,
// HTLC"s into PaymentDescriptor's so we can re-insert them into our
// update log.
incomingHtlcs, outgoingHtlcs, err := lc.extractPayDescs(
diskCommit.CommitHeight, SatPerKWeight(diskCommit.FeePerKw),
diskCommit.CommitHeight,
chainfee.SatPerKWeight(diskCommit.FeePerKw),
diskCommit.Htlcs, localCommitKeys, remoteCommitKeys,
)
if err != nil {
@@ -915,7 +917,7 @@ func (lc *LightningChannel) diskCommitToMemCommit(isLocal bool,
txn: diskCommit.CommitTx,
sig: diskCommit.CommitSig,
fee: diskCommit.CommitFee,
feePerKw: SatPerKWeight(diskCommit.FeePerKw),
feePerKw: chainfee.SatPerKWeight(diskCommit.FeePerKw),
incomingHTLCs: incomingHtlcs,
outgoingHTLCs: outgoingHtlcs,
}
@@ -1509,7 +1511,7 @@ func (lc *LightningChannel) ResetState() {
// if nothing happened.
func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate,
remoteUpdateLog *updateLog, commitHeight uint64,
feeRate SatPerKWeight, remoteCommitKeys *CommitmentKeyRing,
feeRate chainfee.SatPerKWeight, remoteCommitKeys *CommitmentKeyRing,
remoteDustLimit btcutil.Amount) (*PaymentDescriptor, error) {
// Depending on the type of update message we'll map that to a distinct
@@ -1826,7 +1828,8 @@ func (lc *LightningChannel) restoreStateLogs(
for _, logUpdate := range pendingRemoteCommitDiff.LogUpdates {
payDesc, err := lc.logUpdateToPayDesc(
&logUpdate, lc.remoteUpdateLog, pendingHeight,
SatPerKWeight(pendingCommit.FeePerKw), pendingRemoteKeys,
chainfee.SatPerKWeight(pendingCommit.FeePerKw),
pendingRemoteKeys,
lc.channelState.RemoteChanCfg.DustLimit,
)
if err != nil {
@@ -2109,7 +2112,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
// an output on the commitment transaction.
if htlcIsDust(
htlc.Incoming, false,
SatPerKWeight(revokedSnapshot.FeePerKw),
chainfee.SatPerKWeight(revokedSnapshot.FeePerKw),
htlc.Amt.ToSatoshis(), chanState.RemoteChanCfg.DustLimit,
) {
continue
@@ -2198,13 +2201,13 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
// htlcTimeoutFee returns the fee in satoshis required for an HTLC timeout
// transaction based on the current fee rate.
func htlcTimeoutFee(feePerKw SatPerKWeight) btcutil.Amount {
func htlcTimeoutFee(feePerKw chainfee.SatPerKWeight) btcutil.Amount {
return feePerKw.FeeForWeight(input.HtlcTimeoutWeight)
}
// htlcSuccessFee returns the fee in satoshis required for an HTLC success
// transaction based on the current fee rate.
func htlcSuccessFee(feePerKw SatPerKWeight) btcutil.Amount {
func htlcSuccessFee(feePerKw chainfee.SatPerKWeight) btcutil.Amount {
return feePerKw.FeeForWeight(input.HtlcSuccessWeight)
}
@@ -2214,7 +2217,7 @@ func htlcSuccessFee(feePerKw SatPerKWeight) btcutil.Amount {
// require as we currently used second-level HTLC transactions as off-chain
// covenants. Depending on the two bits, we'll either be using a timeout or
// success transaction which have different weights.
func htlcIsDust(incoming, ourCommit bool, feePerKw SatPerKWeight,
func htlcIsDust(incoming, ourCommit bool, feePerKw chainfee.SatPerKWeight,
htlcAmt, dustLimit btcutil.Amount) bool {
// First we'll determine the fee required for this HTLC based on if this is
@@ -2255,7 +2258,7 @@ func htlcIsDust(incoming, ourCommit bool, feePerKw SatPerKWeight,
type htlcView struct {
ourUpdates []*PaymentDescriptor
theirUpdates []*PaymentDescriptor
feePerKw SatPerKWeight
feePerKw chainfee.SatPerKWeight
}
// fetchHTLCView returns all the candidate HTLC updates which should be
@@ -2786,7 +2789,7 @@ func processFeeUpdate(feeUpdate *PaymentDescriptor, nextHeight uint64,
// If the update wasn't already locked in, update the current fee rate
// to reflect this update.
view.feePerKw = SatPerKWeight(feeUpdate.Amount.ToSatoshis())
view.feePerKw = chainfee.SatPerKWeight(feeUpdate.Amount.ToSatoshis())
if mutateState {
*addHeight = nextHeight
@@ -3131,9 +3134,9 @@ func (lc *LightningChannel) validateCommitmentSanity(theirLogCounter,
// Ensure that the fee being applied is enough to be relayed across the
// network in a reasonable time frame.
if feePerKw < FeePerKwFloor {
if feePerKw < chainfee.FeePerKwFloor {
return fmt.Errorf("commitment fee per kw %v below fee floor %v",
feePerKw, FeePerKwFloor)
feePerKw, chainfee.FeePerKwFloor)
}
// If the added HTLCs will decrease the balance, make sure they won't
@@ -5049,7 +5052,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
// Next, we'll obtain HTLC resolutions for all the outgoing HTLC's we
// had on their commitment transaction.
htlcResolutions, err := extractHtlcResolutions(
SatPerKWeight(remoteCommit.FeePerKw), false, signer,
chainfee.SatPerKWeight(remoteCommit.FeePerKw), false, signer,
remoteCommit.Htlcs, keyRing, &chanState.LocalChanCfg,
&chanState.RemoteChanCfg, *commitSpend.SpenderTxHash,
)
@@ -5246,10 +5249,11 @@ type HtlcResolutions struct {
// newOutgoingHtlcResolution generates a new HTLC resolution capable of
// allowing the caller to sweep an outgoing HTLC present on either their, or
// the remote party's commitment transaction.
func newOutgoingHtlcResolution(signer input.Signer, localChanCfg *channeldb.ChannelConfig,
commitHash chainhash.Hash, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
feePerKw SatPerKWeight, dustLimit btcutil.Amount, csvDelay uint32, localCommit bool,
) (*OutgoingHtlcResolution, error) {
func newOutgoingHtlcResolution(signer input.Signer,
localChanCfg *channeldb.ChannelConfig, commitHash chainhash.Hash,
htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
feePerKw chainfee.SatPerKWeight, csvDelay uint32,
localCommit bool) (*OutgoingHtlcResolution, error) {
op := wire.OutPoint{
Hash: commitHash,
@@ -5388,7 +5392,7 @@ func newOutgoingHtlcResolution(signer input.Signer, localChanCfg *channeldb.Chan
// TODO(roasbeef) consolidate code with above func
func newIncomingHtlcResolution(signer input.Signer, localChanCfg *channeldb.ChannelConfig,
commitHash chainhash.Hash, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
feePerKw SatPerKWeight, dustLimit btcutil.Amount, csvDelay uint32,
feePerKw chainfee.SatPerKWeight, csvDelay uint32,
localCommit bool) (*IncomingHtlcResolution, error) {
op := wire.OutPoint{
@@ -5542,7 +5546,7 @@ func (r *OutgoingHtlcResolution) HtlcPoint() wire.OutPoint {
// extractHtlcResolutions creates a series of outgoing HTLC resolutions, and
// the local key used when generating the HTLC scrips. This function is to be
// used in two cases: force close, or a unilateral close.
func extractHtlcResolutions(feePerKw SatPerKWeight, ourCommit bool,
func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, ourCommit bool,
signer input.Signer, htlcs []channeldb.HTLC, keyRing *CommitmentKeyRing,
localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
commitHash chainhash.Hash) (*HtlcResolutions, error) {
@@ -5573,7 +5577,7 @@ func extractHtlcResolutions(feePerKw SatPerKWeight, ourCommit bool,
// as we can satisfy the contract.
ihr, err := newIncomingHtlcResolution(
signer, localChanCfg, commitHash, &htlc, keyRing,
feePerKw, dustLimit, uint32(csvDelay), ourCommit,
feePerKw, uint32(csvDelay), ourCommit,
)
if err != nil {
return nil, err
@@ -5585,7 +5589,7 @@ func extractHtlcResolutions(feePerKw SatPerKWeight, ourCommit bool,
ohr, err := newOutgoingHtlcResolution(
signer, localChanCfg, commitHash, &htlc, keyRing,
feePerKw, dustLimit, uint32(csvDelay), ourCommit,
feePerKw, uint32(csvDelay), ourCommit,
)
if err != nil {
return nil, err
@@ -5763,7 +5767,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
// outgoing HTLC's that we'll need to claim as well.
txHash := commitTx.TxHash()
htlcResolutions, err := extractHtlcResolutions(
SatPerKWeight(localCommit.FeePerKw), true, signer,
chainfee.SatPerKWeight(localCommit.FeePerKw), true, signer,
localCommit.Htlcs, keyRing, &chanState.LocalChanCfg,
&chanState.RemoteChanCfg, txHash,
)
@@ -5981,7 +5985,7 @@ func (lc *LightningChannel) StateSnapshot() *channeldb.ChannelSnapshot {
// validateFeeRate ensures that if the passed fee is applied to the channel,
// and a new commitment is created (which evaluates this fee), then the
// initiator of the channel does not dip below their reserve.
func (lc *LightningChannel) validateFeeRate(feePerKw SatPerKWeight) error {
func (lc *LightningChannel) validateFeeRate(feePerKw chainfee.SatPerKWeight) error {
// We'll ensure that we can accommodate this new fee change, yet still
// be above our reserve balance. Otherwise, we'll reject the fee
// update.
@@ -6029,7 +6033,7 @@ func (lc *LightningChannel) validateFeeRate(feePerKw SatPerKWeight) error {
// UpdateFee initiates a fee update for this channel. Must only be called by
// the channel initiator, and must be called before sending update_fee to
// the remote.
func (lc *LightningChannel) UpdateFee(feePerKw SatPerKWeight) error {
func (lc *LightningChannel) UpdateFee(feePerKw chainfee.SatPerKWeight) error {
lc.Lock()
defer lc.Unlock()
@@ -6057,7 +6061,7 @@ func (lc *LightningChannel) UpdateFee(feePerKw SatPerKWeight) error {
// ReceiveUpdateFee handles an updated fee sent from remote. This method will
// return an error if called as channel initiator.
func (lc *LightningChannel) ReceiveUpdateFee(feePerKw SatPerKWeight) error {
func (lc *LightningChannel) ReceiveUpdateFee(feePerKw chainfee.SatPerKWeight) error {
lc.Lock()
defer lc.Unlock()
@@ -6213,7 +6217,7 @@ func CreateCooperativeCloseTx(fundingTxIn wire.TxIn,
// CalcFee returns the commitment fee to use for the given
// fee rate (fee-per-kw).
func (lc *LightningChannel) CalcFee(feeRate SatPerKWeight) btcutil.Amount {
func (lc *LightningChannel) CalcFee(feeRate chainfee.SatPerKWeight) btcutil.Amount {
return feeRate.FeeForWeight(input.CommitWeight)
}
@@ -6223,7 +6227,7 @@ func (lc *LightningChannel) CalcFee(feeRate SatPerKWeight) btcutil.Amount {
//
// NOTE: This should only be used for channels in which the local commitment is
// the initiator.
func (lc *LightningChannel) MaxFeeRate(maxAllocation float64) SatPerKWeight {
func (lc *LightningChannel) MaxFeeRate(maxAllocation float64) chainfee.SatPerKWeight {
lc.RLock()
defer lc.RUnlock()
@@ -6237,7 +6241,9 @@ func (lc *LightningChannel) MaxFeeRate(maxAllocation float64) SatPerKWeight {
// Ensure the fee rate doesn't dip below the fee floor.
maxFeeRate := maxFee / (float64(weight) / 1000)
return SatPerKWeight(math.Max(maxFeeRate, float64(FeePerKwFloor)))
return chainfee.SatPerKWeight(
math.Max(maxFeeRate, float64(chainfee.FeePerKwFloor)),
)
}
// RemoteNextRevocation returns the channelState's RemoteNextRevocation.
@@ -6260,11 +6266,11 @@ func (lc *LightningChannel) IsInitiator() bool {
// CommitFeeRate returns the current fee rate of the commitment transaction in
// units of sat-per-kw.
func (lc *LightningChannel) CommitFeeRate() SatPerKWeight {
func (lc *LightningChannel) CommitFeeRate() chainfee.SatPerKWeight {
lc.RLock()
defer lc.RUnlock()
return SatPerKWeight(lc.channelState.LocalCommitment.FeePerKw)
return chainfee.SatPerKWeight(lc.channelState.LocalCommitment.FeePerKw)
}
// IsPending returns true if the channel's funding transaction has been fully
+105 -47
View File
@@ -19,6 +19,7 @@ import (
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwire"
)
@@ -456,8 +457,12 @@ func TestCooperativeChannelClosure(t *testing.T) {
aliceDeliveryScript := bobsPrivKey[:]
bobDeliveryScript := testHdSeed[:]
aliceFeeRate := SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)
bobFeeRate := SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw)
aliceFeeRate := chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
)
bobFeeRate := chainfee.SatPerKWeight(
bobChannel.channelState.LocalCommitment.FeePerKw,
)
// We'll store with both Alice and Bob creating a new close proposal
// with the same fee.
@@ -596,7 +601,9 @@ func TestForceClose(t *testing.T) {
// Factoring in the fee rate, Alice's amount should properly reflect
// that we've added two additional HTLC to the commitment transaction.
totalCommitWeight := input.CommitWeight + (input.HtlcWeight * 2)
feePerKw := SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)
feePerKw := chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
)
commitFee := feePerKw.FeeForWeight(totalCommitWeight)
expectedAmount := (aliceChannel.Capacity / 2) - htlcAmount.ToSatoshis() - commitFee
if aliceCommitResolution.SelfOutputSignDesc.Output.Value != int64(expectedAmount) {
@@ -1004,7 +1011,10 @@ func TestHTLCDustLimit(t *testing.T) {
// The amount of the HTLC should be above Alice's dust limit and below
// Bob's dust limit.
htlcSat := (btcutil.Amount(500) + htlcTimeoutFee(
SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)))
chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
),
))
htlcAmount := lnwire.NewMSatFromSatoshis(htlcSat)
htlc, preimage := createHTLC(0, htlcAmount)
@@ -1102,7 +1112,7 @@ func TestHTLCSigNumber(t *testing.T) {
}
// Calculate two values that will be below and above Bob's dust limit.
estimator := NewStaticFeeEstimator(6000, 0)
estimator := chainfee.NewStaticEstimator(6000, 0)
feePerKw, err := estimator.EstimateFeePerKW(1)
if err != nil {
t.Fatalf("unable to get fee: %v", err)
@@ -1268,7 +1278,9 @@ func TestChannelBalanceDustLimit(t *testing.T) {
aliceBalance := aliceChannel.channelState.LocalCommitment.LocalBalance.ToSatoshis()
htlcSat := aliceBalance - defaultFee
htlcSat += htlcSuccessFee(
SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw),
chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
),
)
htlcAmount := lnwire.NewMSatFromSatoshis(htlcSat)
@@ -1366,7 +1378,7 @@ func TestStateUpdatePersistence(t *testing.T) {
}
// Also add a fee update to the update logs.
fee := SatPerKWeight(333)
fee := chainfee.SatPerKWeight(333)
if err := aliceChannel.UpdateFee(fee); err != nil {
t.Fatalf("unable to send fee update")
}
@@ -1779,8 +1791,12 @@ func TestCooperativeCloseDustAdherence(t *testing.T) {
}
defer cleanUp()
aliceFeeRate := SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)
bobFeeRate := SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw)
aliceFeeRate := chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
)
bobFeeRate := chainfee.SatPerKWeight(
bobChannel.channelState.LocalCommitment.FeePerKw,
)
setDustLimit := func(dustVal btcutil.Amount) {
aliceChannel.channelState.LocalChanCfg.DustLimit = dustVal
@@ -1946,7 +1962,7 @@ func TestUpdateFeeAdjustments(t *testing.T) {
// We'll first try to increase the fee rate 5x, this should be able to
// be committed without any issue.
newFee := SatPerKWeight(baseFeeRate * 5)
newFee := chainfee.SatPerKWeight(baseFeeRate * 5)
if err := aliceChannel.UpdateFee(newFee); err != nil {
t.Fatalf("unable to alice update fee: %v", err)
@@ -1964,7 +1980,7 @@ func TestUpdateFeeAdjustments(t *testing.T) {
// We'll now attempt to increase the fee rate 1,000,000x of the base
// fee. This should result in an error as Alice won't be able to pay
// this new fee rate.
newFee = SatPerKWeight(baseFeeRate * 1000000)
newFee = chainfee.SatPerKWeight(baseFeeRate * 1000000)
if err := aliceChannel.UpdateFee(newFee); err == nil {
t.Fatalf("alice should reject the fee rate")
}
@@ -1972,7 +1988,7 @@ func TestUpdateFeeAdjustments(t *testing.T) {
// Finally, we'll attempt to adjust the fee down and use a fee which is
// smaller than the initial base fee rate. The fee application and
// state transition should proceed without issue.
newFee = SatPerKWeight(baseFeeRate / 10)
newFee = chainfee.SatPerKWeight(baseFeeRate / 10)
if err := aliceChannel.UpdateFee(newFee); err != nil {
t.Fatalf("unable to alice update fee: %v", err)
}
@@ -2048,7 +2064,7 @@ func TestUpdateFeeConcurrentSig(t *testing.T) {
}
// Simulate Alice sending update fee message to bob.
fee := SatPerKWeight(333)
fee := chainfee.SatPerKWeight(333)
if err := aliceChannel.UpdateFee(fee); err != nil {
t.Fatalf("unable to send fee update")
}
@@ -2084,7 +2100,7 @@ func TestUpdateFeeConcurrentSig(t *testing.T) {
t.Fatalf("bob unable to process alice's new commitment: %v", err)
}
if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) == fee {
if chainfee.SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) == fee {
t.Fatalf("bob's feePerKw was unexpectedly locked in")
}
@@ -2095,7 +2111,7 @@ func TestUpdateFeeConcurrentSig(t *testing.T) {
t.Fatalf("unable to generate bob revocation: %v", err)
}
if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != fee {
if chainfee.SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != fee {
t.Fatalf("bob's feePerKw was not locked in")
}
}
@@ -2134,7 +2150,7 @@ func TestUpdateFeeSenderCommits(t *testing.T) {
}
// Simulate Alice sending update fee message to bob.
fee := SatPerKWeight(333)
fee := chainfee.SatPerKWeight(333)
aliceChannel.UpdateFee(fee)
bobChannel.ReceiveUpdateFee(fee)
@@ -2154,7 +2170,9 @@ func TestUpdateFeeSenderCommits(t *testing.T) {
t.Fatalf("bob unable to process alice's new commitment: %v", err)
}
if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) == fee {
if chainfee.SatPerKWeight(
bobChannel.channelState.LocalCommitment.FeePerKw,
) == fee {
t.Fatalf("bob's feePerKw was unexpectedly locked in")
}
@@ -2165,7 +2183,9 @@ func TestUpdateFeeSenderCommits(t *testing.T) {
t.Fatalf("unable to generate bob revocation: %v", err)
}
if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != fee {
if chainfee.SatPerKWeight(
bobChannel.channelState.LocalCommitment.FeePerKw,
) != fee {
t.Fatalf("bob's feePerKw was not locked in")
}
@@ -2191,7 +2211,9 @@ func TestUpdateFeeSenderCommits(t *testing.T) {
t.Fatalf("alice unable to process bob's new commitment: %v", err)
}
if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) == fee {
if chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
) == fee {
t.Fatalf("alice's feePerKw was unexpectedly locked in")
}
@@ -2202,7 +2224,9 @@ func TestUpdateFeeSenderCommits(t *testing.T) {
t.Fatalf("unable to revoke alice channel: %v", err)
}
if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) != fee {
if chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
) != fee {
t.Fatalf("alice's feePerKw was not locked in")
}
@@ -2248,7 +2272,7 @@ func TestUpdateFeeReceiverCommits(t *testing.T) {
}
// Simulate Alice sending update fee message to bob
fee := SatPerKWeight(333)
fee := chainfee.SatPerKWeight(333)
aliceChannel.UpdateFee(fee)
bobChannel.ReceiveUpdateFee(fee)
@@ -2296,7 +2320,9 @@ func TestUpdateFeeReceiverCommits(t *testing.T) {
t.Fatalf("alice unable to process bob's new commitment: %v", err)
}
if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) == fee {
if chainfee.SatPerKWeight(
bobChannel.channelState.LocalCommitment.FeePerKw,
) == fee {
t.Fatalf("bob's feePerKw was unexpectedly locked in")
}
@@ -2308,7 +2334,9 @@ func TestUpdateFeeReceiverCommits(t *testing.T) {
t.Fatalf("unable to revoke alice channel: %v", err)
}
if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != fee {
if chainfee.SatPerKWeight(
bobChannel.channelState.LocalCommitment.FeePerKw,
) != fee {
t.Fatalf("bob's feePerKw was not locked in")
}
@@ -2333,7 +2361,9 @@ func TestUpdateFeeReceiverCommits(t *testing.T) {
t.Fatalf("alice unable to process bob's new commitment: %v", err)
}
if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) == fee {
if chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
) == fee {
t.Fatalf("alice's feePerKw was unexpectedly locked in")
}
@@ -2344,7 +2374,9 @@ func TestUpdateFeeReceiverCommits(t *testing.T) {
t.Fatalf("unable to generate bob revocation: %v", err)
}
if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) != fee {
if chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
) != fee {
t.Fatalf("Alice's feePerKw was not locked in")
}
@@ -2372,7 +2404,7 @@ func TestUpdateFeeReceiverSendsUpdate(t *testing.T) {
// Since Alice is the channel initiator, she should fail when receiving
// fee update
fee := SatPerKWeight(333)
fee := chainfee.SatPerKWeight(333)
err = aliceChannel.ReceiveUpdateFee(fee)
if err == nil {
t.Fatalf("expected alice to fail receiving fee update")
@@ -2400,9 +2432,9 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) {
defer cleanUp()
// Simulate Alice sending update fee message to bob.
fee1 := SatPerKWeight(333)
fee2 := SatPerKWeight(333)
fee := SatPerKWeight(333)
fee1 := chainfee.SatPerKWeight(333)
fee2 := chainfee.SatPerKWeight(333)
fee := chainfee.SatPerKWeight(333)
aliceChannel.UpdateFee(fee1)
aliceChannel.UpdateFee(fee2)
aliceChannel.UpdateFee(fee)
@@ -2427,15 +2459,17 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) {
t.Fatalf("bob unable to process alice's new commitment: %v", err)
}
if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) == fee {
if chainfee.SatPerKWeight(
bobChannel.channelState.LocalCommitment.FeePerKw,
) == fee {
t.Fatalf("bob's feePerKw was unexpectedly locked in")
}
// Alice sending more fee updates now should not mess up the old fee
// they both committed to.
fee3 := SatPerKWeight(444)
fee4 := SatPerKWeight(555)
fee5 := SatPerKWeight(666)
fee3 := chainfee.SatPerKWeight(444)
fee4 := chainfee.SatPerKWeight(555)
fee5 := chainfee.SatPerKWeight(666)
aliceChannel.UpdateFee(fee3)
aliceChannel.UpdateFee(fee4)
aliceChannel.UpdateFee(fee5)
@@ -2450,7 +2484,9 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) {
t.Fatalf("unable to generate bob revocation: %v", err)
}
if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != fee {
if chainfee.SatPerKWeight(
bobChannel.channelState.LocalCommitment.FeePerKw,
) != fee {
t.Fatalf("bob's feePerKw was not locked in")
}
@@ -2475,7 +2511,9 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) {
t.Fatalf("alice unable to process bob's new commitment: %v", err)
}
if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) == fee {
if chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
) == fee {
t.Fatalf("alice's feePerKw was unexpectedly locked in")
}
@@ -2486,7 +2524,9 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) {
t.Fatalf("unable to revoke alice channel: %v", err)
}
if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) != fee {
if chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
) != fee {
t.Fatalf("alice's feePerKw was not locked in")
}
@@ -3869,7 +3909,9 @@ func TestFeeUpdateRejectInsaneFee(t *testing.T) {
// Next, we'll try to add a fee rate to Alice which is 1,000,000x her
// starting fee rate.
startingFeeRate := SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)
startingFeeRate := chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
)
newFeeRate := startingFeeRate * 1000000
// Both Alice and Bob should reject this new fee rate as it is far too
@@ -3895,7 +3937,9 @@ func TestChannelRetransmissionFeeUpdate(t *testing.T) {
// First, we'll fetch the current fee rate present within the
// commitment transactions.
startingFeeRate := SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)
startingFeeRate := chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
)
// Next, we'll start a commitment update, with Alice sending a new
// update to double the fee rate of the commitment.
@@ -4034,10 +4078,14 @@ func TestChannelRetransmissionFeeUpdate(t *testing.T) {
}
// Both parties should now have the latest fee rate locked-in.
if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) != newFeeRate {
if chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
) != newFeeRate {
t.Fatalf("alice's feePerKw was not locked in")
}
if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != newFeeRate {
if chainfee.SatPerKWeight(
bobChannel.channelState.LocalCommitment.FeePerKw,
) != newFeeRate {
t.Fatalf("bob's feePerKw was not locked in")
}
@@ -4118,7 +4166,7 @@ func TestFeeUpdateOldDiskFormat(t *testing.T) {
// First, we'll fetch the current fee rate present within the
// commitment transactions.
startingFeeRate := SatPerKWeight(
startingFeeRate := chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
)
newFeeRate := startingFeeRate
@@ -4247,10 +4295,14 @@ func TestFeeUpdateOldDiskFormat(t *testing.T) {
}
// Both parties should now have the latest fee rate locked-in.
if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) != newFeeRate {
if chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
) != newFeeRate {
t.Fatalf("alice's feePerKw was not locked in")
}
if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != newFeeRate {
if chainfee.SatPerKWeight(
bobChannel.channelState.LocalCommitment.FeePerKw,
) != newFeeRate {
t.Fatalf("bob's feePerKw was not locked in")
}
@@ -4272,10 +4324,14 @@ func TestFeeUpdateOldDiskFormat(t *testing.T) {
assertLogItems(0, numHTLCs+1)
// ...and the final fee rate locked in.
if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) != newFeeRate {
if chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
) != newFeeRate {
t.Fatalf("alice's feePerKw was not locked in")
}
if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != newFeeRate {
if chainfee.SatPerKWeight(
bobChannel.channelState.LocalCommitment.FeePerKw,
) != newFeeRate {
t.Fatalf("bob's feePerKw was not locked in")
}
}
@@ -6624,7 +6680,9 @@ func TestChannelMaxFeeRate(t *testing.T) {
}
defer cleanUp()
assertMaxFeeRate := func(maxAlloc float64, expFeeRate SatPerKWeight) {
assertMaxFeeRate := func(maxAlloc float64,
expFeeRate chainfee.SatPerKWeight) {
maxFeeRate := aliceChannel.MaxFeeRate(maxAlloc)
if maxFeeRate != expFeeRate {
t.Fatalf("expected max fee rate of %v with max "+
@@ -6636,5 +6694,5 @@ func TestChannelMaxFeeRate(t *testing.T) {
assertMaxFeeRate(1.0, 690607734)
assertMaxFeeRate(0.001, 690607)
assertMaxFeeRate(0.000001, 690)
assertMaxFeeRate(0.0000001, FeePerKwFloor)
assertMaxFeeRate(0.0000001, chainfee.FeePerKwFloor)
}
+2 -1
View File
@@ -6,6 +6,7 @@ import (
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
)
// Config is a struct which houses configuration parameters which modify the
@@ -42,7 +43,7 @@ type Config struct {
// FeeEstimator is the implementation that the wallet will use for the
// calculation of on-chain transaction fees.
FeeEstimator FeeEstimator
FeeEstimator chainfee.Estimator
// ChainIO is an instance of the BlockChainIO interface. ChainIO is
// used to lookup the existence of outputs within the UTXO set.
+3 -2
View File
@@ -10,6 +10,7 @@ import (
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/wallet/txauthor"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
)
// AddressType is an enum-like type which denotes the possible address types
@@ -172,7 +173,7 @@ type WalletController interface {
// This method also takes the target fee expressed in sat/kw that should
// be used when crafting the transaction.
SendOutputs(outputs []*wire.TxOut,
feeRate SatPerKWeight) (*wire.MsgTx, error)
feeRate chainfee.SatPerKWeight) (*wire.MsgTx, error)
// CreateSimpleTx creates a Bitcoin transaction paying to the specified
// outputs. The transaction is not broadcasted to the network. In the
@@ -184,7 +185,7 @@ type WalletController interface {
// NOTE: The dryRun argument can be set true to create a tx that
// doesn't alter the database. A tx created with this set to true
// SHOULD NOT be broadcasted.
CreateSimpleTx(outputs []*wire.TxOut, feeRate SatPerKWeight,
CreateSimpleTx(outputs []*wire.TxOut, feeRate chainfee.SatPerKWeight,
dryRun bool) (*txauthor.AuthoredTx, error)
// ListUnspentWitness returns all unspent outputs which are version 0
+7 -6
View File
@@ -40,6 +40,7 @@ import (
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwire"
)
@@ -166,7 +167,7 @@ func newPkScript(t *testing.T, w *lnwallet.LightningWallet,
// parties to send on-chain funds to each other.
func sendCoins(t *testing.T, miner *rpctest.Harness,
sender, receiver *lnwallet.LightningWallet, output *wire.TxOut,
feeRate lnwallet.SatPerKWeight) *wire.MsgTx {
feeRate chainfee.SatPerKWeight) *wire.MsgTx { //nolint:unparam
t.Helper()
@@ -330,7 +331,7 @@ func createTestWallet(tempTestDir string, miningNode *rpctest.Harness,
WalletController: wc,
Signer: signer,
ChainIO: bio,
FeeEstimator: lnwallet.NewStaticFeeEstimator(2500, 0),
FeeEstimator: chainfee.NewStaticEstimator(2500, 0),
DefaultConstraints: channeldb.ChannelConstraints{
DustLimit: 500,
MaxPendingAmount: lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin) * 100,
@@ -723,7 +724,7 @@ func testReservationInitiatorBalanceBelowDustCancel(miner *rpctest.Harness,
t.Fatalf("unable to create amt: %v", err)
}
feePerKw := lnwallet.SatPerKWeight(
feePerKw := chainfee.SatPerKWeight(
numBTC * numBTC * btcutil.SatoshiPerBitcoin,
)
req := &lnwallet.InitFundingReserveMsg{
@@ -2151,7 +2152,7 @@ func testChangeOutputSpendConfirmation(r *rpctest.Harness,
//
// TODO(wilmer): replace this once SendOutputs easily supports sending
// all funds in one transaction.
txFeeRate := lnwallet.SatPerKWeight(2500)
txFeeRate := chainfee.SatPerKWeight(2500)
txFee := btcutil.Amount(14380)
output := &wire.TxOut{
Value: int64(aliceBalance - txFee),
@@ -2247,7 +2248,7 @@ func testLastUnusedAddr(miner *rpctest.Harness,
if err != nil {
t.Fatalf("unable to convert addr to script: %v", err)
}
feeRate := lnwallet.SatPerKWeight(2500)
feeRate := chainfee.SatPerKWeight(2500)
output := &wire.TxOut{
Value: 1000000,
PkScript: addrScript,
@@ -2281,7 +2282,7 @@ func testCreateSimpleTx(r *rpctest.Harness, w *lnwallet.LightningWallet,
// The test cases we will run through for all backends.
testCases := []struct {
outVals []int64
feeRate lnwallet.SatPerKWeight
feeRate chainfee.SatPerKWeight
valid bool
}{
{
+2
View File
@@ -7,6 +7,7 @@ import (
"github.com/btcsuite/btcwallet/wtxmgr"
"github.com/lightningnetwork/lnd/build"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
)
// walletLog is a logger that is initialized with no output filters. This
@@ -34,6 +35,7 @@ func UseLogger(logger btclog.Logger) {
btcwallet.UseLogger(logger)
wtxmgr.UseLogger(logger)
chain.UseLogger(logger)
chainfee.UseLogger(logger)
}
// logClosure is used to provide a closure over expensive logging operations
+2 -1
View File
@@ -10,6 +10,7 @@ import (
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwire"
)
@@ -128,7 +129,7 @@ type ChannelReservation struct {
// creation of all channel reservations should be carried out via the
// lnwallet.InitChannelReservation interface.
func NewChannelReservation(capacity, localFundingAmt btcutil.Amount,
commitFeePerKw SatPerKWeight, wallet *LightningWallet,
commitFeePerKw chainfee.SatPerKWeight, wallet *LightningWallet,
id uint64, pushMSat lnwire.MilliSatoshi, chainHash *chainhash.Hash,
flags lnwire.FundingFlag,
tweaklessCommit bool) (*ChannelReservation, error) {
+2 -1
View File
@@ -18,6 +18,7 @@ import (
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/shachain"
)
@@ -233,7 +234,7 @@ func CreateTestChannels(tweaklessCommits bool) (
return nil, nil, nil, err
}
estimator := NewStaticFeeEstimator(6000, 0)
estimator := chainfee.NewStaticEstimator(6000, 0)
feePerKw, err := estimator.EstimateFeePerKW(1)
if err != nil {
return nil, nil, nil, err
+3 -2
View File
@@ -17,6 +17,7 @@ import (
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/shachain"
)
@@ -800,7 +801,7 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) {
height: test.commitment.CommitHeight,
ourBalance: test.commitment.LocalBalance,
theirBalance: test.commitment.RemoteBalance,
feePerKw: SatPerKWeight(test.commitment.FeePerKw),
feePerKw: chainfee.SatPerKWeight(test.commitment.FeePerKw),
dustLimit: tc.dustLimit,
isOurs: true,
}
@@ -843,7 +844,7 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) {
// Generate second-level HTLC transactions for HTLCs in
// commitment tx.
htlcResolutions, err := extractHtlcResolutions(
SatPerKWeight(test.commitment.FeePerKw), true, signer,
chainfee.SatPerKWeight(test.commitment.FeePerKw), true, signer,
htlcs, keys, channel.localChanCfg, channel.remoteChanCfg,
commitTx.TxHash(),
)
+6 -5
View File
@@ -21,6 +21,7 @@ import (
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwallet/chanvalidate"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/shachain"
@@ -89,11 +90,11 @@ type InitFundingReserveMsg struct {
// of initial commitment transactions. In order to ensure timely
// confirmation, it is recommended that this fee should be generous,
// paying some multiple of the accepted base fee rate of the network.
CommitFeePerKw SatPerKWeight
CommitFeePerKw chainfee.SatPerKWeight
// FundingFeePerKw is the fee rate in sat/kw to use for the initial
// funding transaction.
FundingFeePerKw SatPerKWeight
FundingFeePerKw chainfee.SatPerKWeight
// PushMSat is the number of milli-satoshis that should be pushed over
// the responder as part of the initial channel creation.
@@ -1323,7 +1324,7 @@ type coinSelection struct {
// returned, and the value of the resulting funding output. This method locks
// the selected outputs, and a function closure to unlock them in case of an
// error is returned.
func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerKWeight,
func (l *LightningWallet) selectCoinsAndChange(feeRate chainfee.SatPerKWeight,
amt btcutil.Amount, minConfs int32, subtractFees bool) (
*coinSelection, error) {
@@ -1485,7 +1486,7 @@ func selectInputs(amt btcutil.Amount, coins []*Utxo) (btcutil.Amount, []*Utxo, e
// change output to fund amt satoshis, adhering to the specified fee rate. The
// specified fee rate should be expressed in sat/kw for coin selection to
// function properly.
func coinSelect(feeRate SatPerKWeight, amt btcutil.Amount,
func coinSelect(feeRate chainfee.SatPerKWeight, amt btcutil.Amount,
coins []*Utxo) ([]*Utxo, btcutil.Amount, error) {
amtNeeded := amt
@@ -1549,7 +1550,7 @@ func coinSelect(feeRate SatPerKWeight, amt btcutil.Amount,
// coinSelectSubtractFees attempts to select coins such that we'll spend up to
// amt in total after fees, adhering to the specified fee rate. The selected
// coins, the final output and change values are returned.
func coinSelectSubtractFees(feeRate SatPerKWeight, amt,
func coinSelectSubtractFees(feeRate chainfee.SatPerKWeight, amt,
dustLimit btcutil.Amount, coins []*Utxo) ([]*Utxo, btcutil.Amount,
btcutil.Amount, error) {
+6 -3
View File
@@ -5,12 +5,15 @@ import (
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
)
// fundingFee is a helper method that returns the fee estimate used for a tx
// with the given number of inputs and the optional change output. This matches
// the estimate done by the wallet.
func fundingFee(feeRate SatPerKWeight, numInput int, change bool) btcutil.Amount {
func fundingFee(feeRate chainfee.SatPerKWeight, numInput int, // nolint:unparam
change bool) btcutil.Amount {
var weightEstimate input.TxWeightEstimator
// All inputs.
@@ -39,7 +42,7 @@ func fundingFee(feeRate SatPerKWeight, numInput int, change bool) btcutil.Amount
func TestCoinSelect(t *testing.T) {
t.Parallel()
const feeRate = SatPerKWeight(100)
const feeRate = chainfee.SatPerKWeight(100)
const dust = btcutil.Amount(100)
type testCase struct {
@@ -185,7 +188,7 @@ func TestCoinSelect(t *testing.T) {
func TestCoinSelectSubtractFees(t *testing.T) {
t.Parallel()
const feeRate = SatPerKWeight(100)
const feeRate = chainfee.SatPerKWeight(100)
const dustLimit = btcutil.Amount(1000)
const dust = btcutil.Amount(100)