Merge pull request #1644 from wpaulino/kw-fees
multi: switch to sat/kw fees
This commit is contained in:
28 files changed
+408
-446
No files matched your search
@@ -272,11 +272,11 @@ func (b *BtcWallet) GetPrivKey(a btcutil.Address) (*btcec.PrivateKey, error) {
|
||||
//
|
||||
// This is a part of the WalletController interface.
|
||||
func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
|
||||
feeRate lnwallet.SatPerVByte) (*chainhash.Hash, error) {
|
||||
feeRate lnwallet.SatPerKWeight) (*chainhash.Hash, error) {
|
||||
|
||||
// The fee rate is passed in using units of sat/vbyte, so we'll scale
|
||||
// this up to sat/KB as the SendOutputs method requires this unit.
|
||||
feeSatPerKB := btcutil.Amount(feeRate * 1000)
|
||||
// Convert our fee rate from sat/kw to sat/kb since it's required by
|
||||
// SendOutputs.
|
||||
feeSatPerKB := btcutil.Amount(feeRate.FeePerKVByte())
|
||||
|
||||
return b.wallet.SendOutputs(outputs, defaultAccount, 1, feeSatPerKB)
|
||||
}
|
||||
|
||||
@@ -1131,12 +1131,11 @@ func TestHTLCSigNumber(t *testing.T) {
|
||||
}
|
||||
|
||||
// Calculate two values that will be below and above Bob's dust limit.
|
||||
estimator := &StaticFeeEstimator{24}
|
||||
feePerVSize, err := estimator.EstimateFeePerVSize(1)
|
||||
estimator := &StaticFeeEstimator{FeePerKW: 6000}
|
||||
feePerKw, err := estimator.EstimateFeePerKW(1)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get fee: %v", err)
|
||||
}
|
||||
feePerKw := feePerVSize.FeePerKWeight()
|
||||
|
||||
belowDust := btcutil.Amount(500) + htlcTimeoutFee(feePerKw)
|
||||
aboveDust := btcutil.Amount(1400) + htlcSuccessFee(feePerKw)
|
||||
|
||||
+128
-102
@@ -8,38 +8,49 @@ import (
|
||||
"github.com/btcsuite/btcutil"
|
||||
)
|
||||
|
||||
// SatPerVByte represents a fee rate in satoshis per vbyte.
|
||||
type SatPerVByte btcutil.Amount
|
||||
const (
|
||||
// FeePerKwFloor is the lowest fee rate in sat/kw that we should use for
|
||||
// determining transaction fees.
|
||||
FeePerKwFloor SatPerKWeight = 253
|
||||
)
|
||||
|
||||
// FeeForVSize calculates the fee resulting from this fee rate and
|
||||
// the given vsize in vbytes.
|
||||
func (s SatPerVByte) FeeForVSize(vbytes int64) btcutil.Amount {
|
||||
return btcutil.Amount(s) * btcutil.Amount(vbytes)
|
||||
// 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 fee rate into SatPerKWeight.
|
||||
func (s SatPerVByte) FeePerKWeight() SatPerKWeight {
|
||||
return SatPerKWeight(s * 1000 / blockchain.WitnessScaleFactor)
|
||||
// FeePerKWeight converts the current fee rate from sat/kb to sat/kw.
|
||||
func (s SatPerKVByte) FeePerKWeight() SatPerKWeight {
|
||||
return SatPerKWeight(s / blockchain.WitnessScaleFactor)
|
||||
}
|
||||
|
||||
// SatPerKWeight represents a fee rate in satoshis per kilo weight unit.
|
||||
// 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).
|
||||
// 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)
|
||||
}
|
||||
|
||||
// FeeEstimator 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 {
|
||||
// EstimateFeePerVSize takes in a target for the number of blocks until
|
||||
// an initial confirmation and returns the estimated fee expressed in
|
||||
// satoshis/vbyte.
|
||||
EstimateFeePerVSize(numBlocks uint32) (SatPerVByte, error)
|
||||
// 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
|
||||
// it needs to perform its duty.
|
||||
@@ -54,16 +65,16 @@ type FeeEstimator interface {
|
||||
// requests. It is designed to be replaced by a proper fee calculation
|
||||
// implementation.
|
||||
type StaticFeeEstimator struct {
|
||||
// FeeRate is the static fee rate in satoshis-per-vbyte that will be
|
||||
// FeePerKW is the static fee rate in satoshis-per-vbyte that will be
|
||||
// returned by this fee estimator.
|
||||
FeeRate SatPerVByte
|
||||
FeePerKW SatPerKWeight
|
||||
}
|
||||
|
||||
// EstimateFeePerVSize will return a static value for fee calculations.
|
||||
// EstimateFeePerKW will return a static value for fee calculations.
|
||||
//
|
||||
// NOTE: This method is part of the FeeEstimator interface.
|
||||
func (e StaticFeeEstimator) EstimateFeePerVSize(numBlocks uint32) (SatPerVByte, error) {
|
||||
return e.FeeRate, nil
|
||||
func (e StaticFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
|
||||
return e.FeePerKW, nil
|
||||
}
|
||||
|
||||
// Start signals the FeeEstimator to start any processes or goroutines
|
||||
@@ -90,16 +101,16 @@ var _ FeeEstimator = (*StaticFeeEstimator)(nil)
|
||||
// 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 {
|
||||
// fallBackFeeRate is the fall back fee rate in satoshis per vbyte that
|
||||
// is returned if the fee estimator does not yet have enough data to
|
||||
// actually produce fee estimates.
|
||||
fallBackFeeRate SatPerVByte
|
||||
// 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.
|
||||
fallbackFeePerKW SatPerKWeight
|
||||
|
||||
// minFeeRate is the minimum relay fee, in sat/vbyte, of the backend
|
||||
// node. This will be used as the default fee rate of a transaction when
|
||||
// the estimated fee rate is too low to allow the transaction to
|
||||
// propagate through the network.
|
||||
minFeeRate SatPerVByte
|
||||
// minFeePerKW is the minimum fee, in sat/kw, that we should enforce.
|
||||
// This will be used as the default fee rate for a transaction when the
|
||||
// estimated fee rate is too low to allow the transaction to propagate
|
||||
// through the network.
|
||||
minFeePerKW SatPerKWeight
|
||||
|
||||
btcdConn *rpcclient.Client
|
||||
}
|
||||
@@ -110,7 +121,7 @@ type BtcdFeeEstimator struct {
|
||||
// the occasion that the estimator has insufficient data, or returns zero for a
|
||||
// fee estimate.
|
||||
func NewBtcdFeeEstimator(rpcConfig rpcclient.ConnConfig,
|
||||
fallBackFeeRate SatPerVByte) (*BtcdFeeEstimator, error) {
|
||||
fallBackFeeRate SatPerKWeight) (*BtcdFeeEstimator, error) {
|
||||
|
||||
rpcConfig.DisableConnectOnNew = true
|
||||
rpcConfig.DisableAutoReconnect = false
|
||||
@@ -120,8 +131,8 @@ func NewBtcdFeeEstimator(rpcConfig rpcclient.ConnConfig,
|
||||
}
|
||||
|
||||
return &BtcdFeeEstimator{
|
||||
fallBackFeeRate: fallBackFeeRate,
|
||||
btcdConn: chainConn,
|
||||
fallbackFeePerKW: fallBackFeeRate,
|
||||
btcdConn: chainConn,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -146,9 +157,20 @@ func (b *BtcdFeeEstimator) Start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// The fee rate is expressed in sat/KB, so we'll manually convert it to
|
||||
// our desired sat/vbyte rate.
|
||||
b.minFeeRate = SatPerVByte(relayFee / 1000)
|
||||
// The fee rate is expressed in sat/kb, so we'll manually convert it to
|
||||
// our desired sat/kw rate.
|
||||
minRelayFeePerKw := SatPerKVByte(relayFee).FeePerKWeight()
|
||||
|
||||
// By default, we'll use the backend node's minimum relay fee as the
|
||||
// minimum fee rate we'll propose for transacations. However, if this
|
||||
// happens to be lower than our fee floor, we'll enforce that instead.
|
||||
b.minFeePerKW = minRelayFeePerKw
|
||||
if b.minFeePerKW < FeePerKwFloor {
|
||||
b.minFeePerKW = FeePerKwFloor
|
||||
}
|
||||
|
||||
walletLog.Debugf("Using minimum fee rate of %v sat/kw",
|
||||
int64(b.minFeePerKW))
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -163,13 +185,12 @@ func (b *BtcdFeeEstimator) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// EstimateFeePerVSize takes in a target for the number of blocks until an
|
||||
// initial confirmation and returns the estimated fee expressed in
|
||||
// satoshis/vbyte.
|
||||
// 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) EstimateFeePerVSize(numBlocks uint32) (SatPerVByte, error) {
|
||||
feeEstimate, err := b.fetchEstimatePerVSize(numBlocks)
|
||||
func (b *BtcdFeeEstimator) 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
|
||||
@@ -179,16 +200,15 @@ func (b *BtcdFeeEstimator) EstimateFeePerVSize(numBlocks uint32) (SatPerVByte, e
|
||||
fallthrough
|
||||
|
||||
case feeEstimate == 0:
|
||||
return b.fallBackFeeRate, nil
|
||||
return b.fallbackFeePerKW, nil
|
||||
}
|
||||
|
||||
return feeEstimate, nil
|
||||
}
|
||||
|
||||
// fetchEstimate returns a fee estimate for a transaction to be confirmed in
|
||||
// confTarget blocks. The estimate is returned in sat/vbyte.
|
||||
func (b *BtcdFeeEstimator) fetchEstimatePerVSize(
|
||||
confTarget uint32) (SatPerVByte, error) {
|
||||
// confTarget blocks. The estimate is returned in sat/kw.
|
||||
func (b *BtcdFeeEstimator) 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 {
|
||||
@@ -202,23 +222,21 @@ func (b *BtcdFeeEstimator) fetchEstimatePerVSize(
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// The value returned is expressed in fees per KB, while we want
|
||||
// fee-per-byte, so we'll divide by 1000 to map to satoshis-per-byte
|
||||
// before returning the estimate.
|
||||
satPerByte := SatPerVByte(satPerKB / 1000)
|
||||
// Since we use fee rates in sat/kw internally, we'll convert the
|
||||
// estimated fee rate from its sat/kb representation to sat/kw.
|
||||
satPerKw := SatPerKVByte(satPerKB).FeePerKWeight()
|
||||
|
||||
// Before proceeding, we'll make sure that this fee rate respects the
|
||||
// minimum relay fee set on the backend node.
|
||||
if satPerByte < b.minFeeRate {
|
||||
walletLog.Debugf("Using backend node's minimum relay fee rate "+
|
||||
"of %v sat/vbyte", b.minFeeRate)
|
||||
satPerByte = b.minFeeRate
|
||||
// Finally, we'll enforce our fee floor.
|
||||
if satPerKw < b.minFeePerKW {
|
||||
walletLog.Debugf("Estimated fee rate of %v sat/kw is too low, "+
|
||||
"using fee floor of %v sat/kw instead", b.minFeePerKW)
|
||||
satPerKw = b.minFeePerKW
|
||||
}
|
||||
|
||||
walletLog.Debugf("Returning %v sat/vbyte for conf target of %v",
|
||||
int64(satPerByte), confTarget)
|
||||
walletLog.Debugf("Returning %v sat/kw for conf target of %v",
|
||||
int64(satPerKw), confTarget)
|
||||
|
||||
return satPerByte, nil
|
||||
return satPerKw, nil
|
||||
}
|
||||
|
||||
// A compile-time assertion to ensure that BtcdFeeEstimator implements the
|
||||
@@ -229,16 +247,16 @@ var _ FeeEstimator = (*BtcdFeeEstimator)(nil)
|
||||
// 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 {
|
||||
// fallBackFeeRate is the fall back fee rate in satoshis per vbyte that
|
||||
// is returned if the fee estimator does not yet have enough data to
|
||||
// actually produce fee estimates.
|
||||
fallBackFeeRate SatPerVByte
|
||||
// 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.
|
||||
fallbackFeePerKW SatPerKWeight
|
||||
|
||||
// minFeeRate is the minimum relay fee, in sat/vbyte, of the backend
|
||||
// node. This will be used as the default fee rate of a transaction when
|
||||
// the estimated fee rate is too low to allow the transaction to
|
||||
// propagate through the network.
|
||||
minFeeRate SatPerVByte
|
||||
// minFeePerKW is the minimum fee, in sat/kw, that we should enforce.
|
||||
// This will be used as the default fee rate for a transaction when the
|
||||
// estimated fee rate is too low to allow the transaction to propagate
|
||||
// through the network.
|
||||
minFeePerKW SatPerKWeight
|
||||
|
||||
bitcoindConn *rpcclient.Client
|
||||
}
|
||||
@@ -249,7 +267,7 @@ type BitcoindFeeEstimator struct {
|
||||
// is used in the occasion that the estimator has insufficient data, or returns
|
||||
// zero for a fee estimate.
|
||||
func NewBitcoindFeeEstimator(rpcConfig rpcclient.ConnConfig,
|
||||
fallBackFeeRate SatPerVByte) (*BitcoindFeeEstimator, error) {
|
||||
fallBackFeeRate SatPerKWeight) (*BitcoindFeeEstimator, error) {
|
||||
|
||||
rpcConfig.DisableConnectOnNew = true
|
||||
rpcConfig.DisableAutoReconnect = false
|
||||
@@ -261,8 +279,8 @@ func NewBitcoindFeeEstimator(rpcConfig rpcclient.ConnConfig,
|
||||
}
|
||||
|
||||
return &BitcoindFeeEstimator{
|
||||
fallBackFeeRate: fallBackFeeRate,
|
||||
bitcoindConn: chainConn,
|
||||
fallbackFeePerKW: fallBackFeeRate,
|
||||
bitcoindConn: chainConn,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -293,9 +311,20 @@ func (b *BitcoindFeeEstimator) Start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// The fee rate is expressed in sat/KB, so we'll manually convert it to
|
||||
// our desired sat/vbyte rate.
|
||||
b.minFeeRate = SatPerVByte(relayFee / 1000)
|
||||
// The fee rate is expressed in sat/kb, so we'll manually convert it to
|
||||
// our desired sat/kw rate.
|
||||
minRelayFeePerKw := SatPerKVByte(relayFee).FeePerKWeight()
|
||||
|
||||
// By default, we'll use the backend node's minimum relay fee as the
|
||||
// minimum fee rate we'll propose for transacations. However, if this
|
||||
// happens to be lower than our fee floor, we'll enforce that instead.
|
||||
b.minFeePerKW = minRelayFeePerKw
|
||||
if b.minFeePerKW < FeePerKwFloor {
|
||||
b.minFeePerKW = FeePerKwFloor
|
||||
}
|
||||
|
||||
walletLog.Debugf("Using minimum fee rate of %v sat/kw",
|
||||
int64(b.minFeePerKW))
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -308,13 +337,12 @@ func (b *BitcoindFeeEstimator) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// EstimateFeePerVSize takes in a target for the number of blocks until an
|
||||
// initial confirmation and returns the estimated fee expressed in
|
||||
// satoshis/vbyte.
|
||||
// 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) EstimateFeePerVSize(numBlocks uint32) (SatPerVByte, error) {
|
||||
feeEstimate, err := b.fetchEstimatePerVSize(numBlocks)
|
||||
func (b *BitcoindFeeEstimator) 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
|
||||
@@ -324,16 +352,15 @@ func (b *BitcoindFeeEstimator) EstimateFeePerVSize(numBlocks uint32) (SatPerVByt
|
||||
fallthrough
|
||||
|
||||
case feeEstimate == 0:
|
||||
return b.fallBackFeeRate, nil
|
||||
return b.fallbackFeePerKW, nil
|
||||
}
|
||||
|
||||
return feeEstimate, nil
|
||||
}
|
||||
|
||||
// fetchEstimatePerVSize returns a fee estimate for a transaction to be confirmed in
|
||||
// confTarget blocks. The estimate is returned in sat/vbyte.
|
||||
func (b *BitcoindFeeEstimator) fetchEstimatePerVSize(
|
||||
confTarget uint32) (SatPerVByte, error) {
|
||||
// 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) {
|
||||
// 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))
|
||||
@@ -341,45 +368,44 @@ func (b *BitcoindFeeEstimator) fetchEstimatePerVSize(
|
||||
return 0, err
|
||||
}
|
||||
// TODO: Allow selection of economical/conservative modifiers.
|
||||
resp, err := b.bitcoindConn.RawRequest("estimatesmartfee",
|
||||
[]json.RawMessage{target})
|
||||
resp, err := b.bitcoindConn.RawRequest(
|
||||
"estimatesmartfee", []json.RawMessage{target},
|
||||
)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Next, we'll parse the response to get the BTC per KB.
|
||||
feeEstimate := struct {
|
||||
Feerate float64 `json:"feerate"`
|
||||
FeeRate float64 `json:"feerate"`
|
||||
}{}
|
||||
err = json.Unmarshal(resp, &feeEstimate)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Next, we'll convert the returned value to satoshis, as it's
|
||||
// currently returned in BTC.
|
||||
satPerKB, err := btcutil.NewAmount(feeEstimate.Feerate)
|
||||
// Next, we'll convert the returned value to satoshis, as it's currently
|
||||
// returned in BTC.
|
||||
satPerKB, err := btcutil.NewAmount(feeEstimate.FeeRate)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// The value returned is expressed in fees per KB, while we want
|
||||
// fee-per-byte, so we'll divide by 1000 to map to satoshis-per-byte
|
||||
// before returning the estimate.
|
||||
satPerByte := SatPerVByte(satPerKB / 1000)
|
||||
// Since we use fee rates in sat/kw internally, we'll convert the
|
||||
// estimated fee rate from its sat/kb representation to sat/kw.
|
||||
satPerKw := SatPerKVByte(satPerKB).FeePerKWeight()
|
||||
|
||||
// Before proceeding, we'll make sure that this fee rate respects the
|
||||
// minimum relay fee set on the backend node.
|
||||
if satPerByte < b.minFeeRate {
|
||||
walletLog.Debugf("Using backend node's minimum relay fee rate "+
|
||||
"of %v sat/vbyte", b.minFeeRate)
|
||||
satPerByte = b.minFeeRate
|
||||
// Finally, we'll enforce our fee floor.
|
||||
if satPerKw < b.minFeePerKW {
|
||||
walletLog.Debugf("Estimated fee rate of %v sat/kw is too low, "+
|
||||
"using fee floor of %v sat/kw instead", b.minFeePerKW)
|
||||
satPerKw = b.minFeePerKW
|
||||
}
|
||||
|
||||
walletLog.Debugf("Returning %v sat/vbyte for conf target of %v",
|
||||
int64(satPerByte), confTarget)
|
||||
walletLog.Debugf("Returning %v sat/kw for conf target of %v",
|
||||
int64(satPerKw), confTarget)
|
||||
|
||||
return satPerByte, nil
|
||||
return satPerKw, nil
|
||||
}
|
||||
|
||||
// A compile-time assertion to ensure that BitcoindFeeEstimator implements the
|
||||
|
||||
@@ -13,57 +13,56 @@ import (
|
||||
func TestFeeRateTypes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Let our fee rate be 100 sat/vbyte.
|
||||
feePerVSize := lnwallet.SatPerVByte(100)
|
||||
// We'll be calculating the transaction fees for the given measurements
|
||||
// using different fee rates and expecting them to match.
|
||||
const vsize = 300
|
||||
const weight = vsize * 4
|
||||
|
||||
// It is also equivalent to 25000 sat/kw.
|
||||
feePerKw := feePerVSize.FeePerKWeight()
|
||||
if feePerKw != 25000 {
|
||||
t.Fatalf("expected %d sat/kw, got %d sat/kw", 25000,
|
||||
feePerKw)
|
||||
}
|
||||
|
||||
const txVSize = 300
|
||||
|
||||
// We'll now run through a set of values for the fee per vsize type,
|
||||
// making sure the conversion to sat/kw and fee calculation is done
|
||||
// correctly.
|
||||
for f := lnwallet.SatPerVByte(0); f <= 40; f++ {
|
||||
fPerKw := f.FeePerKWeight()
|
||||
|
||||
// The kw is always 250*vsize.
|
||||
if fPerKw != lnwallet.SatPerKWeight(f*250) {
|
||||
t.Fatalf("expected %d sat/kw, got %d sat/kw, when "+
|
||||
"converting %d sat/vbyte", f*250, fPerKw, f)
|
||||
// Test the conversion from sat/kw to sat/kb.
|
||||
for feePerKw := lnwallet.SatPerKWeight(250); feePerKw < 10000; feePerKw += 50 {
|
||||
feePerKB := feePerKw.FeePerKVByte()
|
||||
if feePerKB != lnwallet.SatPerKVByte(feePerKw*4) {
|
||||
t.Fatalf("expected %d sat/kb, got %d sat/kb when "+
|
||||
"converting from %d sat/kw", feePerKw*4,
|
||||
feePerKB, feePerKw)
|
||||
}
|
||||
|
||||
// The tx fee should simply be f*txvsize.
|
||||
fee := f.FeeForVSize(txVSize)
|
||||
if fee != btcutil.Amount(f*txVSize) {
|
||||
t.Fatalf("expected tx fee to be %d sat, was %d sat",
|
||||
f*txVSize, fee)
|
||||
// The resulting transaction fee should be the same when using
|
||||
// both rates.
|
||||
expectedFee := btcutil.Amount(feePerKw * weight / 1000)
|
||||
fee1 := feePerKw.FeeForWeight(weight)
|
||||
if fee1 != expectedFee {
|
||||
t.Fatalf("expected fee of %d sats, got %d sats",
|
||||
expectedFee, fee1)
|
||||
}
|
||||
|
||||
// The weight is 4*vsize. Fee calculation from the fee/kw
|
||||
// should result in the same fee.
|
||||
fee2 := fPerKw.FeeForWeight(txVSize * 4)
|
||||
if fee != fee2 {
|
||||
t.Fatalf("fee calculated from vsize (%d) not equal "+
|
||||
"fee calculated from weight (%d)", fee, fee2)
|
||||
fee2 := feePerKB.FeeForVSize(vsize)
|
||||
if fee2 != expectedFee {
|
||||
t.Fatalf("expected fee of %d sats, got %d sats",
|
||||
expectedFee, fee2)
|
||||
}
|
||||
}
|
||||
|
||||
// Do the same for fee per kw.
|
||||
for f := lnwallet.SatPerKWeight(0); f < 1500; f++ {
|
||||
weight := int64(txVSize * 4)
|
||||
// Test the conversion from sat/kb to sat/kw.
|
||||
for feePerKB := lnwallet.SatPerKVByte(1000); feePerKB < 40000; feePerKB += 1000 {
|
||||
feePerKw := feePerKB.FeePerKWeight()
|
||||
if feePerKw != lnwallet.SatPerKWeight(feePerKB/4) {
|
||||
t.Fatalf("expected %d sat/kw, got %d sat/kw when "+
|
||||
"converting from %d sat/kb", feePerKB/4,
|
||||
feePerKw, feePerKB)
|
||||
}
|
||||
|
||||
// The expected fee is weight*f / 1000, since the fee is
|
||||
// denominated per 1000 wu.
|
||||
expFee := btcutil.Amount(weight) * btcutil.Amount(f) / 1000
|
||||
fee := f.FeeForWeight(weight)
|
||||
if fee != expFee {
|
||||
t.Fatalf("expected fee to be %d sat, was %d",
|
||||
fee, expFee)
|
||||
// The resulting transaction fee should be the same when using
|
||||
// both rates.
|
||||
expectedFee := btcutil.Amount(feePerKB * vsize / 1000)
|
||||
fee1 := feePerKB.FeeForVSize(vsize)
|
||||
if fee1 != expectedFee {
|
||||
t.Fatalf("expected fee of %d sats, got %d sats",
|
||||
expectedFee, fee1)
|
||||
}
|
||||
fee2 := feePerKw.FeeForWeight(weight)
|
||||
if fee2 != expectedFee {
|
||||
t.Fatalf("expected fee of %d sats, got %d sats",
|
||||
expectedFee, fee2)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,22 +72,22 @@ func TestFeeRateTypes(t *testing.T) {
|
||||
func TestStaticFeeEstimator(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const feePerVSize = 100
|
||||
const feePerKw = lnwallet.FeePerKwFloor
|
||||
|
||||
feeEstimator := &lnwallet.StaticFeeEstimator{
|
||||
FeeRate: feePerVSize,
|
||||
FeePerKW: feePerKw,
|
||||
}
|
||||
if err := feeEstimator.Start(); err != nil {
|
||||
t.Fatalf("unable to start fee estimator: %v", err)
|
||||
}
|
||||
defer feeEstimator.Stop()
|
||||
|
||||
feeRate, err := feeEstimator.EstimateFeePerVSize(6)
|
||||
feeRate, err := feeEstimator.EstimateFeePerKW(6)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get fee rate: %v", err)
|
||||
}
|
||||
|
||||
if feeRate != feePerVSize {
|
||||
t.Fatalf("expected fee rate %v, got %v", feePerVSize, feeRate)
|
||||
if feeRate != feePerKw {
|
||||
t.Fatalf("expected fee rate %v, got %v", feePerKw, feeRate)
|
||||
}
|
||||
}
|
||||
@@ -154,13 +154,13 @@ type WalletController interface {
|
||||
// error should be returned.
|
||||
GetPrivKey(a btcutil.Address) (*btcec.PrivateKey, error)
|
||||
|
||||
// SendOutputs funds, signs, and broadcasts a Bitcoin transaction
|
||||
// paying out to the specified outputs. In the case the wallet has
|
||||
// insufficient funds, or the outputs are non-standard, an error should
|
||||
// be returned. This method also takes the target fee expressed in
|
||||
// sat/vbyte that should be used when crafting the transaction.
|
||||
// SendOutputs funds, signs, and broadcasts a Bitcoin transaction paying
|
||||
// out to the specified outputs. In the case the wallet has insufficient
|
||||
// funds, or the outputs are non-standard, an error should be returned.
|
||||
// This method also takes the target fee expressed in sat/kw that should
|
||||
// be used when crafting the transaction.
|
||||
SendOutputs(outputs []*wire.TxOut,
|
||||
feeRate SatPerVByte) (*chainhash.Hash, error)
|
||||
feeRate SatPerKWeight) (*chainhash.Hash, error)
|
||||
|
||||
// ListUnspentWitness returns all unspent outputs which are version 0
|
||||
// witness programs. The 'confirms' parameter indicates the minimum
|
||||
|
||||
+53
-48
@@ -186,7 +186,7 @@ func loadTestCredits(miner *rpctest.Harness, w *lnwallet.LightningWallet,
|
||||
Value: int64(satoshiPerOutput),
|
||||
PkScript: script,
|
||||
}
|
||||
if _, err := miner.SendOutputs([]*wire.TxOut{output}, 10); err != nil {
|
||||
if _, err := miner.SendOutputs([]*wire.TxOut{output}, 2500); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -249,7 +249,7 @@ func createTestWallet(tempTestDir string, miningNode *rpctest.Harness,
|
||||
WalletController: wc,
|
||||
Signer: signer,
|
||||
ChainIO: bio,
|
||||
FeeEstimator: lnwallet.StaticFeeEstimator{FeeRate: 10},
|
||||
FeeEstimator: lnwallet.StaticFeeEstimator{FeePerKW: 2500},
|
||||
DefaultConstraints: channeldb.ChannelConstraints{
|
||||
DustLimit: 500,
|
||||
MaxPendingAmount: lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin) * 100,
|
||||
@@ -290,14 +290,14 @@ func testDualFundingReservationWorkflow(miner *rpctest.Harness,
|
||||
|
||||
// Alice initiates a channel funded with 5 BTC for each side, so 10 BTC
|
||||
// total. She also generates 2 BTC in change.
|
||||
feeRate, err := alice.Cfg.FeeEstimator.EstimateFeePerVSize(1)
|
||||
feePerKw, err := alice.Cfg.FeeEstimator.EstimateFeePerKW(1)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to query fee estimator: %v", err)
|
||||
}
|
||||
feePerKw := feeRate.FeePerKWeight()
|
||||
aliceChanReservation, err := alice.InitChannelReservation(
|
||||
fundingAmount*2, fundingAmount, 0, feePerKw, feeRate,
|
||||
bobPub, bobAddr, chainHash, lnwire.FFAnnounceChannel)
|
||||
fundingAmount*2, fundingAmount, 0, feePerKw, feePerKw, bobPub,
|
||||
bobAddr, chainHash, lnwire.FFAnnounceChannel,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to initialize funding reservation: %v", err)
|
||||
}
|
||||
@@ -325,9 +325,10 @@ func testDualFundingReservationWorkflow(miner *rpctest.Harness,
|
||||
// Bob does the same, generating his own contribution. He then also
|
||||
// receives' Alice's contribution, and consumes that so we can continue
|
||||
// the funding process.
|
||||
bobChanReservation, err := bob.InitChannelReservation(fundingAmount*2,
|
||||
fundingAmount, 0, feePerKw, feeRate, alicePub, aliceAddr,
|
||||
chainHash, lnwire.FFAnnounceChannel)
|
||||
bobChanReservation, err := bob.InitChannelReservation(
|
||||
fundingAmount*2, fundingAmount, 0, feePerKw, feePerKw, alicePub,
|
||||
aliceAddr, chainHash, lnwire.FFAnnounceChannel,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("bob unable to init channel reservation: %v", err)
|
||||
}
|
||||
@@ -476,14 +477,13 @@ func testFundingTransactionLockedOutputs(miner *rpctest.Harness,
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create amt: %v", err)
|
||||
}
|
||||
feeRate, err := alice.Cfg.FeeEstimator.EstimateFeePerVSize(1)
|
||||
feePerKw, err := alice.Cfg.FeeEstimator.EstimateFeePerKW(1)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to query fee estimator: %v", err)
|
||||
}
|
||||
feePerKw := feeRate.FeePerKWeight()
|
||||
_, err = alice.InitChannelReservation(fundingAmount,
|
||||
fundingAmount, 0, feePerKw, feeRate, bobPub, bobAddr, chainHash,
|
||||
lnwire.FFAnnounceChannel,
|
||||
_, err = alice.InitChannelReservation(
|
||||
fundingAmount, fundingAmount, 0, feePerKw, feePerKw, bobPub,
|
||||
bobAddr, chainHash, lnwire.FFAnnounceChannel,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to initialize funding reservation 1: %v", err)
|
||||
@@ -496,9 +496,10 @@ func testFundingTransactionLockedOutputs(miner *rpctest.Harness,
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create amt: %v", err)
|
||||
}
|
||||
failedReservation, err := alice.InitChannelReservation(amt, amt, 0,
|
||||
feePerKw, feeRate, bobPub, bobAddr, chainHash,
|
||||
lnwire.FFAnnounceChannel)
|
||||
failedReservation, err := alice.InitChannelReservation(
|
||||
amt, amt, 0, feePerKw, feePerKw, bobPub, bobAddr, chainHash,
|
||||
lnwire.FFAnnounceChannel,
|
||||
)
|
||||
if err == nil {
|
||||
t.Fatalf("not error returned, should fail on coin selection")
|
||||
}
|
||||
@@ -513,28 +514,28 @@ func testFundingTransactionLockedOutputs(miner *rpctest.Harness,
|
||||
func testFundingCancellationNotEnoughFunds(miner *rpctest.Harness,
|
||||
alice, _ *lnwallet.LightningWallet, t *testing.T) {
|
||||
|
||||
feeRate, err := alice.Cfg.FeeEstimator.EstimateFeePerVSize(1)
|
||||
feePerKw, err := alice.Cfg.FeeEstimator.EstimateFeePerKW(1)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to query fee estimator: %v", err)
|
||||
}
|
||||
feePerKw := feeRate.FeePerKWeight()
|
||||
|
||||
// Create a reservation for 44 BTC.
|
||||
fundingAmount, err := btcutil.NewAmount(44)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create amt: %v", err)
|
||||
}
|
||||
chanReservation, err := alice.InitChannelReservation(fundingAmount,
|
||||
fundingAmount, 0, feePerKw, feeRate, bobPub, bobAddr, chainHash,
|
||||
lnwire.FFAnnounceChannel)
|
||||
chanReservation, err := alice.InitChannelReservation(
|
||||
fundingAmount, fundingAmount, 0, feePerKw, feePerKw, bobPub,
|
||||
bobAddr, chainHash, lnwire.FFAnnounceChannel,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to initialize funding reservation: %v", err)
|
||||
}
|
||||
|
||||
// Attempt to create another channel with 44 BTC, this should fail.
|
||||
_, err = alice.InitChannelReservation(fundingAmount,
|
||||
fundingAmount, 0, feePerKw, feeRate, bobPub, bobAddr, chainHash,
|
||||
lnwire.FFAnnounceChannel,
|
||||
_, err = alice.InitChannelReservation(
|
||||
fundingAmount, fundingAmount, 0, feePerKw, feePerKw, bobPub,
|
||||
bobAddr, chainHash, lnwire.FFAnnounceChannel,
|
||||
)
|
||||
if _, ok := err.(*lnwallet.ErrInsufficientFunds); !ok {
|
||||
t.Fatalf("coin selection succeeded should have insufficient funds: %v",
|
||||
@@ -565,7 +566,7 @@ func testFundingCancellationNotEnoughFunds(miner *rpctest.Harness,
|
||||
|
||||
// Request to fund a new channel should now succeed.
|
||||
_, err = alice.InitChannelReservation(fundingAmount, fundingAmount,
|
||||
0, feePerKw, feeRate, bobPub, bobAddr, chainHash,
|
||||
0, feePerKw, feePerKw, bobPub, bobAddr, chainHash,
|
||||
lnwire.FFAnnounceChannel)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to initialize funding reservation: %v", err)
|
||||
@@ -575,15 +576,15 @@ func testFundingCancellationNotEnoughFunds(miner *rpctest.Harness,
|
||||
func testCancelNonExistentReservation(miner *rpctest.Harness,
|
||||
alice, _ *lnwallet.LightningWallet, t *testing.T) {
|
||||
|
||||
feeRate, err := alice.Cfg.FeeEstimator.EstimateFeePerVSize(1)
|
||||
feePerKw, err := alice.Cfg.FeeEstimator.EstimateFeePerKW(1)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to query fee estimator: %v", err)
|
||||
}
|
||||
|
||||
// Create our own reservation, give it some ID.
|
||||
res, err := lnwallet.NewChannelReservation(
|
||||
10000, 10000, feeRate.FeePerKWeight(), alice,
|
||||
22, 10, &testHdSeed, lnwire.FFAnnounceChannel,
|
||||
10000, 10000, feePerKw, alice, 22, 10, &testHdSeed,
|
||||
lnwire.FFAnnounceChannel,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create res: %v", err)
|
||||
@@ -602,14 +603,17 @@ func testReservationInitiatorBalanceBelowDustCancel(miner *rpctest.Harness,
|
||||
// We'll attempt to create a new reservation with an extremely high fee
|
||||
// rate. This should push our balance into the negative and result in a
|
||||
// failure to create the reservation.
|
||||
fundingAmount, err := btcutil.NewAmount(4)
|
||||
const numBTC = 4
|
||||
fundingAmount, err := btcutil.NewAmount(numBTC)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create amt: %v", err)
|
||||
}
|
||||
feePerVSize := lnwallet.SatPerVByte(btcutil.SatoshiPerBitcoin * 4 / 100)
|
||||
feePerKw := feePerVSize.FeePerKWeight()
|
||||
|
||||
feePerKw := lnwallet.SatPerKWeight(
|
||||
numBTC * numBTC * btcutil.SatoshiPerBitcoin,
|
||||
)
|
||||
_, err = alice.InitChannelReservation(
|
||||
fundingAmount, fundingAmount, 0, feePerKw, feePerVSize, bobPub,
|
||||
fundingAmount, fundingAmount, 0, feePerKw, feePerKw, bobPub,
|
||||
bobAddr, chainHash, lnwire.FFAnnounceChannel,
|
||||
)
|
||||
switch {
|
||||
@@ -677,14 +681,14 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness,
|
||||
t.Fatalf("unable to create amt: %v", err)
|
||||
}
|
||||
pushAmt := lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin)
|
||||
feeRate, err := alice.Cfg.FeeEstimator.EstimateFeePerVSize(1)
|
||||
feePerKw, err := alice.Cfg.FeeEstimator.EstimateFeePerKW(1)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to query fee estimator: %v", err)
|
||||
}
|
||||
feePerKw := feeRate.FeePerKWeight()
|
||||
aliceChanReservation, err := alice.InitChannelReservation(fundingAmt,
|
||||
fundingAmt, pushAmt, feePerKw, feeRate, bobPub, bobAddr, chainHash,
|
||||
lnwire.FFAnnounceChannel)
|
||||
aliceChanReservation, err := alice.InitChannelReservation(
|
||||
fundingAmt, fundingAmt, pushAmt, feePerKw, feePerKw, bobPub,
|
||||
bobAddr, chainHash, lnwire.FFAnnounceChannel,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to init channel reservation: %v", err)
|
||||
}
|
||||
@@ -712,9 +716,10 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness,
|
||||
|
||||
// Next, Bob receives the initial request, generates a corresponding
|
||||
// reservation initiation, then consume Alice's contribution.
|
||||
bobChanReservation, err := bob.InitChannelReservation(fundingAmt, 0,
|
||||
pushAmt, feePerKw, feeRate, alicePub, aliceAddr, chainHash,
|
||||
lnwire.FFAnnounceChannel)
|
||||
bobChanReservation, err := bob.InitChannelReservation(
|
||||
fundingAmt, 0, pushAmt, feePerKw, feePerKw, alicePub, aliceAddr,
|
||||
chainHash, lnwire.FFAnnounceChannel,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create bob reservation: %v", err)
|
||||
}
|
||||
@@ -901,7 +906,7 @@ func testListTransactionDetails(miner *rpctest.Harness,
|
||||
Value: outputAmt,
|
||||
PkScript: script,
|
||||
}
|
||||
txid, err := miner.SendOutputs([]*wire.TxOut{output}, 10)
|
||||
txid, err := miner.SendOutputs([]*wire.TxOut{output}, 2500)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send coinbase: %v", err)
|
||||
}
|
||||
@@ -1004,7 +1009,7 @@ func testListTransactionDetails(miner *rpctest.Harness,
|
||||
t.Fatalf("unable to make output script: %v", err)
|
||||
}
|
||||
burnOutput := wire.NewTxOut(outputAmt, outputScript)
|
||||
burnTXID, err := alice.SendOutputs([]*wire.TxOut{burnOutput}, 10)
|
||||
burnTXID, err := alice.SendOutputs([]*wire.TxOut{burnOutput}, 2500)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create burn tx: %v", err)
|
||||
}
|
||||
@@ -1118,7 +1123,7 @@ func testTransactionSubscriptions(miner *rpctest.Harness,
|
||||
Value: outputAmt,
|
||||
PkScript: script,
|
||||
}
|
||||
txid, err := miner.SendOutputs([]*wire.TxOut{output}, 10)
|
||||
txid, err := miner.SendOutputs([]*wire.TxOut{output}, 2500)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send coinbase: %v", err)
|
||||
}
|
||||
@@ -1318,7 +1323,7 @@ func testPublishTransaction(r *rpctest.Harness,
|
||||
Value: btcutil.SatoshiPerBitcoin,
|
||||
PkScript: keyScript,
|
||||
}
|
||||
txid, err := alice.SendOutputs([]*wire.TxOut{newOutput}, 10)
|
||||
txid, err := alice.SendOutputs([]*wire.TxOut{newOutput}, 2500)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create output: %v", err)
|
||||
}
|
||||
@@ -1563,7 +1568,7 @@ func testSignOutputUsingTweaks(r *rpctest.Harness,
|
||||
Value: btcutil.SatoshiPerBitcoin,
|
||||
PkScript: keyScript,
|
||||
}
|
||||
txid, err := alice.SendOutputs([]*wire.TxOut{newOutput}, 10)
|
||||
txid, err := alice.SendOutputs([]*wire.TxOut{newOutput}, 2500)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create output: %v", err)
|
||||
}
|
||||
@@ -1689,7 +1694,7 @@ func testReorgWalletBalance(r *rpctest.Harness, w *lnwallet.LightningWallet,
|
||||
Value: 1e8,
|
||||
PkScript: script,
|
||||
}
|
||||
txid, err := w.SendOutputs([]*wire.TxOut{output}, 10)
|
||||
txid, err := w.SendOutputs([]*wire.TxOut{output}, 2500)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send outputs: %v", err)
|
||||
}
|
||||
@@ -2083,7 +2088,7 @@ func runTests(t *testing.T, walletDriver *lnwallet.WalletDriver,
|
||||
}
|
||||
|
||||
case "neutrino":
|
||||
feeEstimator = lnwallet.StaticFeeEstimator{FeeRate: 250}
|
||||
feeEstimator = lnwallet.StaticFeeEstimator{FeePerKW: 62500}
|
||||
|
||||
// Set some package-level variable to speed up
|
||||
// operation for tests.
|
||||
|
||||
@@ -229,12 +229,11 @@ func CreateTestChannels() (*LightningChannel, *LightningChannel, func(), error)
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
estimator := &StaticFeeEstimator{24}
|
||||
feePerVSize, err := estimator.EstimateFeePerVSize(1)
|
||||
estimator := &StaticFeeEstimator{FeePerKW: 6000}
|
||||
feePerKw, err := estimator.EstimateFeePerKW(1)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
feePerKw := feePerVSize.FeePerKWeight()
|
||||
commitFee := calcStaticFee(0)
|
||||
|
||||
aliceCommit := channeldb.ChannelCommitment{
|
||||
|
||||
+24
-23
@@ -81,9 +81,9 @@ type initFundingReserveMsg struct {
|
||||
// paying some multiple of the accepted base fee rate of the network.
|
||||
commitFeePerKw SatPerKWeight
|
||||
|
||||
// fundingFeePerVSize is the fee rate in sat/vbyte to use for the
|
||||
// initial funding transaction.
|
||||
fundingFeePerVSize SatPerVByte
|
||||
// fundingFeePerKw is the fee rate in sat/kw to use for the initial
|
||||
// funding transaction.
|
||||
fundingFeePerKw SatPerKWeight
|
||||
|
||||
// pushMSat is the number of milli-satoshis that should be pushed over
|
||||
// the responder as part of the initial channel creation.
|
||||
@@ -413,7 +413,7 @@ out:
|
||||
// commitment transaction is valid.
|
||||
func (l *LightningWallet) InitChannelReservation(
|
||||
capacity, ourFundAmt btcutil.Amount, pushMSat lnwire.MilliSatoshi,
|
||||
commitFeePerKw SatPerKWeight, fundingFeePerVSize SatPerVByte,
|
||||
commitFeePerKw SatPerKWeight, fundingFeePerKw SatPerKWeight,
|
||||
theirID *btcec.PublicKey, theirAddr net.Addr,
|
||||
chainHash *chainhash.Hash, flags lnwire.FundingFlag) (*ChannelReservation, error) {
|
||||
|
||||
@@ -421,17 +421,17 @@ func (l *LightningWallet) InitChannelReservation(
|
||||
respChan := make(chan *ChannelReservation, 1)
|
||||
|
||||
l.msgChan <- &initFundingReserveMsg{
|
||||
chainHash: chainHash,
|
||||
nodeID: theirID,
|
||||
nodeAddr: theirAddr,
|
||||
fundingAmount: ourFundAmt,
|
||||
capacity: capacity,
|
||||
commitFeePerKw: commitFeePerKw,
|
||||
fundingFeePerVSize: fundingFeePerVSize,
|
||||
pushMSat: pushMSat,
|
||||
flags: flags,
|
||||
err: errChan,
|
||||
resp: respChan,
|
||||
chainHash: chainHash,
|
||||
nodeID: theirID,
|
||||
nodeAddr: theirAddr,
|
||||
fundingAmount: ourFundAmt,
|
||||
capacity: capacity,
|
||||
commitFeePerKw: commitFeePerKw,
|
||||
fundingFeePerKw: fundingFeePerKw,
|
||||
pushMSat: pushMSat,
|
||||
flags: flags,
|
||||
err: errChan,
|
||||
resp: respChan,
|
||||
}
|
||||
|
||||
return <-respChan, <-errChan
|
||||
@@ -479,10 +479,10 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg
|
||||
// don't need to perform any coin selection. Otherwise, attempt to
|
||||
// obtain enough coins to meet the required funding amount.
|
||||
if req.fundingAmount != 0 {
|
||||
// Coin selection is done on the basis of sat-per-vbyte, we'll
|
||||
// use the passed sat/vbyte passed in to perform coin selection.
|
||||
// Coin selection is done on the basis of sat/kw, so we'll use
|
||||
// the fee rate passed in to perform coin selection.
|
||||
err := l.selectCoinsAndChange(
|
||||
req.fundingFeePerVSize, req.fundingAmount,
|
||||
req.fundingFeePerKw, req.fundingAmount,
|
||||
reservation.ourContribution,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -1266,7 +1266,7 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) {
|
||||
// within the passed contribution's inputs. If necessary, a change address will
|
||||
// also be generated.
|
||||
// TODO(roasbeef): remove hardcoded fees and req'd confs for outputs.
|
||||
func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerVByte,
|
||||
func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerKWeight,
|
||||
amt btcutil.Amount, contribution *ChannelContribution) error {
|
||||
|
||||
// We hold the coin select mutex while querying for outputs, and
|
||||
@@ -1276,7 +1276,7 @@ func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerVByte,
|
||||
defer l.coinSelectMtx.Unlock()
|
||||
|
||||
walletLog.Infof("Performing funding tx coin selection using %v "+
|
||||
"sat/vbyte as fee rate", int64(feeRate))
|
||||
"sat/kw as fee rate", int64(feeRate))
|
||||
|
||||
// Find all unlocked unspent witness outputs with greater than 1
|
||||
// confirmation.
|
||||
@@ -1385,9 +1385,9 @@ func selectInputs(amt btcutil.Amount, coins []*Utxo) (btcutil.Amount, []*Utxo, e
|
||||
|
||||
// coinSelect attempts to select a sufficient amount of coins, including a
|
||||
// change output to fund amt satoshis, adhering to the specified fee rate. The
|
||||
// specified fee rate should be expressed in sat/vbyte for coin selection to
|
||||
// specified fee rate should be expressed in sat/kw for coin selection to
|
||||
// function properly.
|
||||
func coinSelect(feeRate SatPerVByte, amt btcutil.Amount,
|
||||
func coinSelect(feeRate SatPerKWeight, amt btcutil.Amount,
|
||||
coins []*Utxo) ([]*Utxo, btcutil.Amount, error) {
|
||||
|
||||
amtNeeded := amt
|
||||
@@ -1431,7 +1431,8 @@ func coinSelect(feeRate SatPerVByte, amt btcutil.Amount,
|
||||
// amount isn't enough to pay fees, then increase the requested
|
||||
// coin amount by the estimate required fee, performing another
|
||||
// round of coin selection.
|
||||
requiredFee := feeRate.FeeForVSize(int64(weightEstimate.VSize()))
|
||||
totalWeight := int64(weightEstimate.Weight())
|
||||
requiredFee := feeRate.FeeForWeight(totalWeight)
|
||||
if overShootAmt < requiredFee {
|
||||
amtNeeded = amt + requiredFee
|
||||
continue
|
||||
|
||||
Reference in new issue
Block a user