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

+11 -11
View File
@@ -3,38 +3,38 @@ package sweep
import (
"sync"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
)
// mockFeeEstimator implements a mock fee estimator. It closely resembles
// lnwallet.StaticFeeEstimator with the addition that fees can be changed for
// testing purposes in a thread safe manner.
type mockFeeEstimator struct {
feePerKW lnwallet.SatPerKWeight
feePerKW chainfee.SatPerKWeight
relayFee lnwallet.SatPerKWeight
relayFee chainfee.SatPerKWeight
blocksToFee map[uint32]lnwallet.SatPerKWeight
blocksToFee map[uint32]chainfee.SatPerKWeight
// A closure that when set is used instead of the
// mockFeeEstimator.EstimateFeePerKW method.
estimateFeePerKW func(numBlocks uint32) (lnwallet.SatPerKWeight, error)
estimateFeePerKW func(numBlocks uint32) (chainfee.SatPerKWeight, error)
lock sync.Mutex
}
func newMockFeeEstimator(feePerKW,
relayFee lnwallet.SatPerKWeight) *mockFeeEstimator {
relayFee chainfee.SatPerKWeight) *mockFeeEstimator {
return &mockFeeEstimator{
feePerKW: feePerKW,
relayFee: relayFee,
blocksToFee: make(map[uint32]lnwallet.SatPerKWeight),
blocksToFee: make(map[uint32]chainfee.SatPerKWeight),
}
}
func (e *mockFeeEstimator) updateFees(feePerKW,
relayFee lnwallet.SatPerKWeight) {
relayFee chainfee.SatPerKWeight) {
e.lock.Lock()
defer e.lock.Unlock()
@@ -44,7 +44,7 @@ func (e *mockFeeEstimator) updateFees(feePerKW,
}
func (e *mockFeeEstimator) EstimateFeePerKW(numBlocks uint32) (
lnwallet.SatPerKWeight, error) {
chainfee.SatPerKWeight, error) {
e.lock.Lock()
defer e.lock.Unlock()
@@ -60,7 +60,7 @@ func (e *mockFeeEstimator) EstimateFeePerKW(numBlocks uint32) (
return e.feePerKW, nil
}
func (e *mockFeeEstimator) RelayFeePerKW() lnwallet.SatPerKWeight {
func (e *mockFeeEstimator) RelayFeePerKW() chainfee.SatPerKWeight {
e.lock.Lock()
defer e.lock.Unlock()
@@ -75,4 +75,4 @@ func (e *mockFeeEstimator) Stop() error {
return nil
}
var _ lnwallet.FeeEstimator = (*mockFeeEstimator)(nil)
var _ chainfee.Estimator = (*mockFeeEstimator)(nil)
+17 -16
View File
@@ -16,13 +16,14 @@ import (
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
)
const (
// DefaultMaxFeeRate is the default maximum fee rate allowed within the
// UtxoSweeper. The current value is equivalent to a fee rate of 10,000
// sat/vbyte.
DefaultMaxFeeRate = lnwallet.FeePerKwFloor * 1e4
DefaultMaxFeeRate = chainfee.FeePerKwFloor * 1e4
// DefaultFeeRateBucketSize is the default size of fee rate buckets
// we'll use when clustering inputs into buckets with similar fee rates
@@ -92,7 +93,7 @@ type pendingInput struct {
// lastFeeRate is the most recent fee rate used for this input within a
// transaction broadcast to the network.
lastFeeRate lnwallet.SatPerKWeight
lastFeeRate chainfee.SatPerKWeight
}
// pendingInputs is a type alias for a set of pending inputs.
@@ -101,7 +102,7 @@ type pendingInputs = map[wire.OutPoint]*pendingInput
// inputCluster is a helper struct to gather a set of pending inputs that should
// be swept with the specified fee rate.
type inputCluster struct {
sweepFeeRate lnwallet.SatPerKWeight
sweepFeeRate chainfee.SatPerKWeight
inputs pendingInputs
}
@@ -126,7 +127,7 @@ type PendingInput struct {
// LastFeeRate is the most recent fee rate used for the input being
// swept within a transaction broadcast to the network.
LastFeeRate lnwallet.SatPerKWeight
LastFeeRate chainfee.SatPerKWeight
// BroadcastAttempts is the number of attempts we've made to sweept the
// input.
@@ -182,7 +183,7 @@ type UtxoSweeper struct {
currentOutputScript []byte
relayFeeRate lnwallet.SatPerKWeight
relayFeeRate chainfee.SatPerKWeight
quit chan struct{}
wg sync.WaitGroup
@@ -197,7 +198,7 @@ type UtxoSweeperConfig struct {
// FeeEstimator is used when crafting sweep transactions to estimate
// the necessary fee relative to the expected size of the sweep
// transaction.
FeeEstimator lnwallet.FeeEstimator
FeeEstimator chainfee.Estimator
// PublishTransaction facilitates the process of broadcasting a signed
// transaction to the appropriate network.
@@ -235,7 +236,7 @@ type UtxoSweeperConfig struct {
// MaxFeeRate is the the maximum fee rate allowed within the
// UtxoSweeper.
MaxFeeRate lnwallet.SatPerKWeight
MaxFeeRate chainfee.SatPerKWeight
// FeeRateBucketSize is the default size of fee rate buckets we'll use
// when clustering inputs into buckets with similar fee rates within the
@@ -403,7 +404,7 @@ func (s *UtxoSweeper) SweepInput(input input.Input,
// feeRateForPreference returns a fee rate for the given fee preference. It
// ensures that the fee rate respects the bounds of the UtxoSweeper.
func (s *UtxoSweeper) feeRateForPreference(
feePreference FeePreference) (lnwallet.SatPerKWeight, error) {
feePreference FeePreference) (chainfee.SatPerKWeight, error) {
// Ensure a type of fee preference is specified to prevent using a
// default below.
@@ -637,10 +638,10 @@ func (s *UtxoSweeper) collector(blockEpochs <-chan *chainntnfs.BlockEpoch) {
// bucketForFeeReate determines the proper bucket for a fee rate. This is done
// in order to batch inputs with similar fee rates together.
func (s *UtxoSweeper) bucketForFeeRate(
feeRate lnwallet.SatPerKWeight) lnwallet.SatPerKWeight {
feeRate chainfee.SatPerKWeight) chainfee.SatPerKWeight {
minBucket := s.relayFeeRate + lnwallet.SatPerKWeight(s.cfg.FeeRateBucketSize)
return lnwallet.SatPerKWeight(
minBucket := s.relayFeeRate + chainfee.SatPerKWeight(s.cfg.FeeRateBucketSize)
return chainfee.SatPerKWeight(
math.Ceil(float64(feeRate) / float64(minBucket)),
)
}
@@ -650,8 +651,8 @@ func (s *UtxoSweeper) bucketForFeeRate(
// sweep fee rate, which is determined by calculating the average fee rate of
// all inputs within that cluster.
func (s *UtxoSweeper) clusterBySweepFeeRate() []inputCluster {
bucketInputs := make(map[lnwallet.SatPerKWeight]pendingInputs)
inputFeeRates := make(map[wire.OutPoint]lnwallet.SatPerKWeight)
bucketInputs := make(map[chainfee.SatPerKWeight]pendingInputs)
inputFeeRates := make(map[wire.OutPoint]chainfee.SatPerKWeight)
// First, we'll group together all inputs with similar fee rates. This
// is done by determining the fee rate bucket they should belong in.
@@ -678,11 +679,11 @@ func (s *UtxoSweeper) clusterBySweepFeeRate() []inputCluster {
// calculating the average fee rate of the inputs within each set.
inputClusters := make([]inputCluster, 0, len(bucketInputs))
for _, inputs := range bucketInputs {
var sweepFeeRate lnwallet.SatPerKWeight
var sweepFeeRate chainfee.SatPerKWeight
for op := range inputs {
sweepFeeRate += inputFeeRates[op]
}
sweepFeeRate /= lnwallet.SatPerKWeight(len(inputs))
sweepFeeRate /= chainfee.SatPerKWeight(len(inputs))
inputClusters = append(inputClusters, inputCluster{
sweepFeeRate: sweepFeeRate,
inputs: inputs,
@@ -836,7 +837,7 @@ func (s *UtxoSweeper) getInputLists(cluster inputCluster,
// sweep takes a set of preselected inputs, creates a sweep tx and publishes the
// tx. The output address is only marked as used if the publish succeeds.
func (s *UtxoSweeper) sweep(inputs inputSet, feeRate lnwallet.SatPerKWeight,
func (s *UtxoSweeper) sweep(inputs inputSet, feeRate chainfee.SatPerKWeight,
currentHeight int32) error {
// Generate an output script if there isn't an unused script available.
+6 -5
View File
@@ -15,6 +15,7 @@ import (
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
)
var (
@@ -99,7 +100,7 @@ func createSweeperTestContext(t *testing.T) *sweeperTestContext {
backend := newMockBackend(notifier)
estimator := newMockFeeEstimator(10000, lnwallet.FeePerKwFloor)
estimator := newMockFeeEstimator(10000, chainfee.FeePerKwFloor)
publishChan := make(chan wire.MsgTx, 2)
ctx := &sweeperTestContext{
@@ -314,7 +315,7 @@ func assertTxSweepsInputs(t *testing.T, sweepTx *wire.MsgTx,
// NOTE: This assumes that transactions only have one output, as this is the
// only type of transaction the UtxoSweeper can create at the moment.
func assertTxFeeRate(t *testing.T, tx *wire.MsgTx,
expectedFeeRate lnwallet.SatPerKWeight, inputs ...input.Input) {
expectedFeeRate chainfee.SatPerKWeight, inputs ...input.Input) {
t.Helper()
@@ -994,11 +995,11 @@ func TestDifferentFeePreferences(t *testing.T) {
// this to ensure the sweeper can broadcast distinct transactions for
// each sweep with a different fee preference.
lowFeePref := FeePreference{ConfTarget: 12}
lowFeeRate := lnwallet.SatPerKWeight(5000)
lowFeeRate := chainfee.SatPerKWeight(5000)
ctx.estimator.blocksToFee[lowFeePref.ConfTarget] = lowFeeRate
highFeePref := FeePreference{ConfTarget: 6}
highFeeRate := lnwallet.SatPerKWeight(10000)
highFeeRate := chainfee.SatPerKWeight(10000)
ctx.estimator.blocksToFee[highFeePref.ConfTarget] = highFeeRate
input1 := spendableInputs[0]
@@ -1116,7 +1117,7 @@ func TestBumpFeeRBF(t *testing.T) {
ctx := createSweeperTestContext(t)
lowFeePref := FeePreference{ConfTarget: 144}
lowFeeRate := lnwallet.FeePerKwFloor
lowFeeRate := chainfee.FeePerKwFloor
ctx.estimator.blocksToFee[lowFeePref.ConfTarget] = lowFeeRate
// We'll first try to bump the fee of an output currently unknown to the
+4 -4
View File
@@ -11,7 +11,7 @@ import (
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/wallet/txrules"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
)
var (
@@ -31,7 +31,7 @@ type inputSet []input.Input
// inputs are skipped. No input sets with a total value after fees below the
// dust limit are returned.
func generateInputPartitionings(sweepableInputs []input.Input,
relayFeePerKW, feePerKW lnwallet.SatPerKWeight,
relayFeePerKW, feePerKW chainfee.SatPerKWeight,
maxInputsPerTx int) ([]inputSet, error) {
// Calculate dust limit based on the P2WPKH output script of the sweep
@@ -116,7 +116,7 @@ func generateInputPartitionings(sweepableInputs []input.Input,
// minimizing any negative externalities we cause for the Bitcoin system as a
// whole.
func getPositiveYieldInputs(sweepableInputs []input.Input, maxInputs int,
feePerKW lnwallet.SatPerKWeight) (int, btcutil.Amount) {
feePerKW chainfee.SatPerKWeight) (int, btcutil.Amount) {
var weightEstimate input.TxWeightEstimator
@@ -169,7 +169,7 @@ func getPositiveYieldInputs(sweepableInputs []input.Input, maxInputs int,
// createSweepTx builds a signed tx spending the inputs to a the output script.
func createSweepTx(inputs []input.Input, outputPkScript []byte,
currentBlockHeight uint32, feePerKw lnwallet.SatPerKWeight,
currentBlockHeight uint32, feePerKw chainfee.SatPerKWeight,
signer input.Signer) (*wire.MsgTx, error) {
inputs, txWeight := getWeightEstimate(inputs)
+9 -8
View File
@@ -9,6 +9,7 @@ import (
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
)
const (
@@ -27,7 +28,7 @@ type FeePreference struct {
// FeeRate if non-zero, signals a fee pre fence expressed in the fee
// rate expressed in sat/kw for a particular transaction.
FeeRate lnwallet.SatPerKWeight
FeeRate chainfee.SatPerKWeight
}
// String returns a human-readable string of the fee preference.
@@ -42,8 +43,8 @@ func (p FeePreference) String() string {
// an estimator, a confirmation target, and a manual value for sat/byte. A
// value is chosen based on the two free parameters as one, or both of them can
// be zero.
func DetermineFeePerKw(feeEstimator lnwallet.FeeEstimator,
feePref FeePreference) (lnwallet.SatPerKWeight, error) {
func DetermineFeePerKw(feeEstimator chainfee.Estimator,
feePref FeePreference) (chainfee.SatPerKWeight, error) {
switch {
// If both values are set, then we'll return an error as we require a
@@ -70,12 +71,12 @@ func DetermineFeePerKw(feeEstimator lnwallet.FeeEstimator,
// internally.
case feePref.FeeRate != 0:
feePerKW := feePref.FeeRate
if feePerKW < lnwallet.FeePerKwFloor {
if feePerKW < chainfee.FeePerKwFloor {
log.Infof("Manual fee rate input of %d sat/kw is "+
"too low, using %d sat/kw instead", feePerKW,
lnwallet.FeePerKwFloor)
chainfee.FeePerKwFloor)
feePerKW = lnwallet.FeePerKwFloor
feePerKW = chainfee.FeePerKwFloor
}
return feePerKW, nil
@@ -152,10 +153,10 @@ type WalletSweepPackage struct {
// by the delivery address. The sweep transaction will be crafted with the
// target fee rate, and will use the utxoSource and outpointLocker as sources
// for wallet funds.
func CraftSweepAllTx(feeRate lnwallet.SatPerKWeight, blockHeight uint32,
func CraftSweepAllTx(feeRate chainfee.SatPerKWeight, blockHeight uint32,
deliveryAddr btcutil.Address, coinSelectLocker CoinSelectionLocker,
utxoSource UtxoSource, outpointLocker OutpointLocker,
feeEstimator lnwallet.FeeEstimator,
feeEstimator chainfee.Estimator,
signer input.Signer) (*WalletSweepPackage, error) {
// TODO(roasbeef): turn off ATPL as well when available?
+6 -5
View File
@@ -10,6 +10,7 @@ import (
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
)
// TestDetermineFeePerKw tests that given a fee preference, the
@@ -17,8 +18,8 @@ import (
func TestDetermineFeePerKw(t *testing.T) {
t.Parallel()
defaultFee := lnwallet.SatPerKWeight(999)
relayFee := lnwallet.SatPerKWeight(300)
defaultFee := chainfee.SatPerKWeight(999)
relayFee := chainfee.SatPerKWeight(300)
feeEstimator := newMockFeeEstimator(defaultFee, relayFee)
@@ -35,7 +36,7 @@ func TestDetermineFeePerKw(t *testing.T) {
// fee is the value the DetermineFeePerKw should return given
// the FeePreference above
fee lnwallet.SatPerKWeight
fee chainfee.SatPerKWeight
// fail determines if this test case should fail or not.
fail bool
@@ -43,9 +44,9 @@ func TestDetermineFeePerKw(t *testing.T) {
// A fee rate below the fee rate floor should output the floor.
{
feePref: FeePreference{
FeeRate: lnwallet.SatPerKWeight(99),
FeeRate: chainfee.SatPerKWeight(99),
},
fee: lnwallet.FeePerKwFloor,
fee: chainfee.FeePerKwFloor,
},
// A fee rate above the floor, should pass through and return