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:
parent
fcf81ed8ff
commit
777ed104a3
@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -78,7 +79,7 @@ type BreachConfig struct {
|
|||||||
// Estimator is used by the breach arbiter to determine an appropriate
|
// Estimator is used by the breach arbiter to determine an appropriate
|
||||||
// fee level when generating, signing, and broadcasting sweep
|
// fee level when generating, signing, and broadcasting sweep
|
||||||
// transactions.
|
// transactions.
|
||||||
Estimator lnwallet.FeeEstimator
|
Estimator chainfee.Estimator
|
||||||
|
|
||||||
// GenSweepScript generates the receiving scripts for swept outputs.
|
// GenSweepScript generates the receiving scripts for swept outputs.
|
||||||
GenSweepScript func() ([]byte, error)
|
GenSweepScript func() ([]byte, error)
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/shachain"
|
"github.com/lightningnetwork/lnd/shachain"
|
||||||
)
|
)
|
||||||
@ -1675,7 +1676,7 @@ func createTestArbiter(t *testing.T, contractBreaches chan *ContractBreachEvent,
|
|||||||
ba := newBreachArbiter(&BreachConfig{
|
ba := newBreachArbiter(&BreachConfig{
|
||||||
CloseLink: func(_ *wire.OutPoint, _ htlcswitch.ChannelCloseType) {},
|
CloseLink: func(_ *wire.OutPoint, _ htlcswitch.ChannelCloseType) {},
|
||||||
DB: db,
|
DB: db,
|
||||||
Estimator: lnwallet.NewStaticFeeEstimator(12500, 0),
|
Estimator: chainfee.NewStaticEstimator(12500, 0),
|
||||||
GenSweepScript: func() ([]byte, error) { return nil, nil },
|
GenSweepScript: func() ([]byte, error) { return nil, nil },
|
||||||
ContractBreaches: contractBreaches,
|
ContractBreaches: contractBreaches,
|
||||||
Signer: signer,
|
Signer: signer,
|
||||||
@ -1824,7 +1825,7 @@ func createInitChannels(revocationWindow int) (*lnwallet.LightningChannel, *lnwa
|
|||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
estimator := lnwallet.NewStaticFeeEstimator(12500, 0)
|
estimator := chainfee.NewStaticEstimator(12500, 0)
|
||||||
feePerKw, err := estimator.EstimateFeePerKW(1)
|
feePerKw, err := estimator.EstimateFeePerKW(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
|
@ -30,6 +30,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
|
"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/routing/chainview"
|
"github.com/lightningnetwork/lnd/routing/chainview"
|
||||||
)
|
)
|
||||||
@ -55,11 +56,11 @@ const (
|
|||||||
|
|
||||||
// defaultBitcoinStaticFeePerKW is the fee rate of 50 sat/vbyte
|
// defaultBitcoinStaticFeePerKW is the fee rate of 50 sat/vbyte
|
||||||
// expressed in sat/kw.
|
// expressed in sat/kw.
|
||||||
defaultBitcoinStaticFeePerKW = lnwallet.SatPerKWeight(12500)
|
defaultBitcoinStaticFeePerKW = chainfee.SatPerKWeight(12500)
|
||||||
|
|
||||||
// defaultLitecoinStaticFeePerKW is the fee rate of 200 sat/vbyte
|
// defaultLitecoinStaticFeePerKW is the fee rate of 200 sat/vbyte
|
||||||
// expressed in sat/kw.
|
// expressed in sat/kw.
|
||||||
defaultLitecoinStaticFeePerKW = lnwallet.SatPerKWeight(50000)
|
defaultLitecoinStaticFeePerKW = chainfee.SatPerKWeight(50000)
|
||||||
|
|
||||||
// btcToLtcConversionRate is a fixed ratio used in order to scale up
|
// btcToLtcConversionRate is a fixed ratio used in order to scale up
|
||||||
// payments when running on the Litecoin chain.
|
// payments when running on the Litecoin chain.
|
||||||
@ -112,7 +113,7 @@ func (c chainCode) String() string {
|
|||||||
type chainControl struct {
|
type chainControl struct {
|
||||||
chainIO lnwallet.BlockChainIO
|
chainIO lnwallet.BlockChainIO
|
||||||
|
|
||||||
feeEstimator lnwallet.FeeEstimator
|
feeEstimator chainfee.Estimator
|
||||||
|
|
||||||
signer input.Signer
|
signer input.Signer
|
||||||
|
|
||||||
@ -161,7 +162,7 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
|
|||||||
FeeRate: cfg.Bitcoin.FeeRate,
|
FeeRate: cfg.Bitcoin.FeeRate,
|
||||||
TimeLockDelta: cfg.Bitcoin.TimeLockDelta,
|
TimeLockDelta: cfg.Bitcoin.TimeLockDelta,
|
||||||
}
|
}
|
||||||
cc.feeEstimator = lnwallet.NewStaticFeeEstimator(
|
cc.feeEstimator = chainfee.NewStaticEstimator(
|
||||||
defaultBitcoinStaticFeePerKW, 0,
|
defaultBitcoinStaticFeePerKW, 0,
|
||||||
)
|
)
|
||||||
case litecoinChain:
|
case litecoinChain:
|
||||||
@ -171,7 +172,7 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
|
|||||||
FeeRate: cfg.Litecoin.FeeRate,
|
FeeRate: cfg.Litecoin.FeeRate,
|
||||||
TimeLockDelta: cfg.Litecoin.TimeLockDelta,
|
TimeLockDelta: cfg.Litecoin.TimeLockDelta,
|
||||||
}
|
}
|
||||||
cc.feeEstimator = lnwallet.NewStaticFeeEstimator(
|
cc.feeEstimator = chainfee.NewStaticEstimator(
|
||||||
defaultLitecoinStaticFeePerKW, 0,
|
defaultLitecoinStaticFeePerKW, 0,
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
@ -219,8 +220,8 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
|
|||||||
if cfg.NeutrinoMode.FeeURL != "" {
|
if cfg.NeutrinoMode.FeeURL != "" {
|
||||||
ltndLog.Infof("Using API fee estimator!")
|
ltndLog.Infof("Using API fee estimator!")
|
||||||
|
|
||||||
estimator := lnwallet.NewWebAPIFeeEstimator(
|
estimator := chainfee.NewWebAPIEstimator(
|
||||||
lnwallet.SparseConfFeeSource{
|
chainfee.SparseConfFeeSource{
|
||||||
URL: cfg.NeutrinoMode.FeeURL,
|
URL: cfg.NeutrinoMode.FeeURL,
|
||||||
},
|
},
|
||||||
defaultBitcoinStaticFeePerKW,
|
defaultBitcoinStaticFeePerKW,
|
||||||
@ -323,8 +324,8 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
|
|||||||
// if we're using bitcoind as a backend, then we can
|
// if we're using bitcoind as a backend, then we can
|
||||||
// use live fee estimates, rather than a statically
|
// use live fee estimates, rather than a statically
|
||||||
// coded value.
|
// coded value.
|
||||||
fallBackFeeRate := lnwallet.SatPerKVByte(25 * 1000)
|
fallBackFeeRate := chainfee.SatPerKVByte(25 * 1000)
|
||||||
cc.feeEstimator, err = lnwallet.NewBitcoindFeeEstimator(
|
cc.feeEstimator, err = chainfee.NewBitcoindEstimator(
|
||||||
*rpcConfig, fallBackFeeRate.FeePerKWeight(),
|
*rpcConfig, fallBackFeeRate.FeePerKWeight(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -340,8 +341,8 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
|
|||||||
// if we're using litecoind as a backend, then we can
|
// if we're using litecoind as a backend, then we can
|
||||||
// use live fee estimates, rather than a statically
|
// use live fee estimates, rather than a statically
|
||||||
// coded value.
|
// coded value.
|
||||||
fallBackFeeRate := lnwallet.SatPerKVByte(25 * 1000)
|
fallBackFeeRate := chainfee.SatPerKVByte(25 * 1000)
|
||||||
cc.feeEstimator, err = lnwallet.NewBitcoindFeeEstimator(
|
cc.feeEstimator, err = chainfee.NewBitcoindEstimator(
|
||||||
*rpcConfig, fallBackFeeRate.FeePerKWeight(),
|
*rpcConfig, fallBackFeeRate.FeePerKWeight(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -445,8 +446,8 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
|
|||||||
// if we're using btcd as a backend, then we can use
|
// if we're using btcd as a backend, then we can use
|
||||||
// live fee estimates, rather than a statically coded
|
// live fee estimates, rather than a statically coded
|
||||||
// value.
|
// value.
|
||||||
fallBackFeeRate := lnwallet.SatPerKVByte(25 * 1000)
|
fallBackFeeRate := chainfee.SatPerKVByte(25 * 1000)
|
||||||
cc.feeEstimator, err = lnwallet.NewBtcdFeeEstimator(
|
cc.feeEstimator, err = chainfee.NewBtcdEstimator(
|
||||||
*rpcConfig, fallBackFeeRate.FeePerKWeight(),
|
*rpcConfig, fallBackFeeRate.FeePerKWeight(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -150,7 +151,7 @@ type channelCloser struct {
|
|||||||
// passed configuration, and delivery+fee preference. The final argument should
|
// passed configuration, and delivery+fee preference. The final argument should
|
||||||
// only be populated iff, we're the initiator of this closing request.
|
// only be populated iff, we're the initiator of this closing request.
|
||||||
func newChannelCloser(cfg chanCloseCfg, deliveryScript []byte,
|
func newChannelCloser(cfg chanCloseCfg, deliveryScript []byte,
|
||||||
idealFeePerKw lnwallet.SatPerKWeight, negotiationHeight uint32,
|
idealFeePerKw chainfee.SatPerKWeight, negotiationHeight uint32,
|
||||||
closeReq *htlcswitch.ChanClose) *channelCloser {
|
closeReq *htlcswitch.ChanClose) *channelCloser {
|
||||||
|
|
||||||
// Given the target fee-per-kw, we'll compute what our ideal _total_
|
// Given the target fee-per-kw, we'll compute what our ideal _total_
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/sweep"
|
"github.com/lightningnetwork/lnd/sweep"
|
||||||
)
|
)
|
||||||
@ -131,7 +132,7 @@ type ChainArbitratorConfig struct {
|
|||||||
Signer input.Signer
|
Signer input.Signer
|
||||||
|
|
||||||
// FeeEstimator will be used to return fee estimates.
|
// FeeEstimator will be used to return fee estimates.
|
||||||
FeeEstimator lnwallet.FeeEstimator
|
FeeEstimator chainfee.Estimator
|
||||||
|
|
||||||
// ChainIO allows us to query the state of the current main chain.
|
// ChainIO allows us to query the state of the current main chain.
|
||||||
ChainIO lnwallet.BlockChainIO
|
ChainIO lnwallet.BlockChainIO
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnpeer"
|
"github.com/lightningnetwork/lnd/lnpeer"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/routing"
|
"github.com/lightningnetwork/lnd/routing"
|
||||||
"golang.org/x/crypto/salsa20"
|
"golang.org/x/crypto/salsa20"
|
||||||
@ -230,7 +231,7 @@ type fundingConfig struct {
|
|||||||
|
|
||||||
// FeeEstimator calculates appropriate fee rates based on historical
|
// FeeEstimator calculates appropriate fee rates based on historical
|
||||||
// transaction information.
|
// transaction information.
|
||||||
FeeEstimator lnwallet.FeeEstimator
|
FeeEstimator chainfee.Estimator
|
||||||
|
|
||||||
// Notifier is used by the FundingManager to determine when the
|
// Notifier is used by the FundingManager to determine when the
|
||||||
// channel's funding transaction has been confirmed on the blockchain
|
// channel's funding transaction has been confirmed on the blockchain
|
||||||
@ -1218,7 +1219,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
|
|||||||
NodeAddr: fmsg.peer.Address(),
|
NodeAddr: fmsg.peer.Address(),
|
||||||
LocalFundingAmt: 0,
|
LocalFundingAmt: 0,
|
||||||
RemoteFundingAmt: amt,
|
RemoteFundingAmt: amt,
|
||||||
CommitFeePerKw: lnwallet.SatPerKWeight(msg.FeePerKiloWeight),
|
CommitFeePerKw: chainfee.SatPerKWeight(msg.FeePerKiloWeight),
|
||||||
FundingFeePerKw: 0,
|
FundingFeePerKw: 0,
|
||||||
PushMSat: msg.PushAmount,
|
PushMSat: msg.PushAmount,
|
||||||
Flags: msg.ChannelFlags,
|
Flags: msg.ChannelFlags,
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnpeer"
|
"github.com/lightningnetwork/lnd/lnpeer"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -218,7 +219,7 @@ func createTestWallet(cdb *channeldb.DB, netParams *chaincfg.Params,
|
|||||||
notifier chainntnfs.ChainNotifier, wc lnwallet.WalletController,
|
notifier chainntnfs.ChainNotifier, wc lnwallet.WalletController,
|
||||||
signer input.Signer, keyRing keychain.SecretKeyRing,
|
signer input.Signer, keyRing keychain.SecretKeyRing,
|
||||||
bio lnwallet.BlockChainIO,
|
bio lnwallet.BlockChainIO,
|
||||||
estimator lnwallet.FeeEstimator) (*lnwallet.LightningWallet, error) {
|
estimator chainfee.Estimator) (*lnwallet.LightningWallet, error) {
|
||||||
|
|
||||||
wallet, err := lnwallet.NewLightningWallet(lnwallet.Config{
|
wallet, err := lnwallet.NewLightningWallet(lnwallet.Config{
|
||||||
Database: cdb,
|
Database: cdb,
|
||||||
@ -247,7 +248,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
|
|||||||
options ...cfgOption) (*testNode, error) {
|
options ...cfgOption) (*testNode, error) {
|
||||||
|
|
||||||
netParams := activeNetParams.Params
|
netParams := activeNetParams.Params
|
||||||
estimator := lnwallet.NewStaticFeeEstimator(62500, 0)
|
estimator := chainfee.NewStaticEstimator(62500, 0)
|
||||||
|
|
||||||
chainNotifier := &mockNotifier{
|
chainNotifier := &mockNotifier{
|
||||||
oneConfChannel: make(chan *chainntnfs.TxConfirmation, 1),
|
oneConfChannel: make(chan *chainntnfs.TxConfirmation, 1),
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnpeer"
|
"github.com/lightningnetwork/lnd/lnpeer"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/queue"
|
"github.com/lightningnetwork/lnd/queue"
|
||||||
"github.com/lightningnetwork/lnd/ticker"
|
"github.com/lightningnetwork/lnd/ticker"
|
||||||
@ -199,7 +200,7 @@ type ChannelLinkConfig struct {
|
|||||||
// FeeEstimator is an instance of a live fee estimator which will be
|
// FeeEstimator is an instance of a live fee estimator which will be
|
||||||
// used to dynamically regulate the current fee of the commitment
|
// used to dynamically regulate the current fee of the commitment
|
||||||
// transaction to ensure timely confirmation.
|
// transaction to ensure timely confirmation.
|
||||||
FeeEstimator lnwallet.FeeEstimator
|
FeeEstimator chainfee.Estimator
|
||||||
|
|
||||||
// hodl.Mask is a bitvector composed of hodl.Flags, specifying breakpoints
|
// hodl.Mask is a bitvector composed of hodl.Flags, specifying breakpoints
|
||||||
// for HTLC forwarding internal to the switch.
|
// for HTLC forwarding internal to the switch.
|
||||||
@ -570,7 +571,7 @@ func (l *channelLink) markReestablished() {
|
|||||||
// chain in a timely manner. The returned value is expressed in fee-per-kw, as
|
// chain in a timely manner. The returned value is expressed in fee-per-kw, as
|
||||||
// this is the native rate used when computing the fee for commitment
|
// this is the native rate used when computing the fee for commitment
|
||||||
// transactions, and the second-level HTLC transactions.
|
// transactions, and the second-level HTLC transactions.
|
||||||
func (l *channelLink) sampleNetworkFee() (lnwallet.SatPerKWeight, error) {
|
func (l *channelLink) sampleNetworkFee() (chainfee.SatPerKWeight, error) {
|
||||||
// We'll first query for the sat/kw recommended to be confirmed within 3
|
// We'll first query for the sat/kw recommended to be confirmed within 3
|
||||||
// blocks.
|
// blocks.
|
||||||
feePerKw, err := l.cfg.FeeEstimator.EstimateFeePerKW(3)
|
feePerKw, err := l.cfg.FeeEstimator.EstimateFeePerKW(3)
|
||||||
@ -587,7 +588,7 @@ func (l *channelLink) sampleNetworkFee() (lnwallet.SatPerKWeight, error) {
|
|||||||
// shouldAdjustCommitFee returns true if we should update our commitment fee to
|
// shouldAdjustCommitFee returns true if we should update our commitment fee to
|
||||||
// match that of the network fee. We'll only update our commitment fee if the
|
// match that of the network fee. We'll only update our commitment fee if the
|
||||||
// network fee is +/- 10% to our network fee.
|
// network fee is +/- 10% to our network fee.
|
||||||
func shouldAdjustCommitFee(netFee, chanFee lnwallet.SatPerKWeight) bool {
|
func shouldAdjustCommitFee(netFee, chanFee chainfee.SatPerKWeight) bool {
|
||||||
switch {
|
switch {
|
||||||
// If the network fee is greater than the commitment fee, then we'll
|
// If the network fee is greater than the commitment fee, then we'll
|
||||||
// switch to it if it's at least 10% greater than the commit fee.
|
// switch to it if it's at least 10% greater than the commit fee.
|
||||||
@ -1061,7 +1062,7 @@ out:
|
|||||||
// fee rate to our max fee allocation.
|
// fee rate to our max fee allocation.
|
||||||
commitFee := l.channel.CommitFeeRate()
|
commitFee := l.channel.CommitFeeRate()
|
||||||
maxFee := l.channel.MaxFeeRate(l.cfg.MaxFeeAllocation)
|
maxFee := l.channel.MaxFeeRate(l.cfg.MaxFeeAllocation)
|
||||||
newCommitFee := lnwallet.SatPerKWeight(
|
newCommitFee := chainfee.SatPerKWeight(
|
||||||
math.Min(float64(netFee), float64(maxFee)),
|
math.Min(float64(netFee), float64(maxFee)),
|
||||||
)
|
)
|
||||||
if !shouldAdjustCommitFee(newCommitFee, commitFee) {
|
if !shouldAdjustCommitFee(newCommitFee, commitFee) {
|
||||||
@ -1894,7 +1895,7 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) {
|
|||||||
case *lnwire.UpdateFee:
|
case *lnwire.UpdateFee:
|
||||||
// We received fee update from peer. If we are the initiator we
|
// We received fee update from peer. If we are the initiator we
|
||||||
// will fail the channel, if not we will apply the update.
|
// will fail the channel, if not we will apply the update.
|
||||||
fee := lnwallet.SatPerKWeight(msg.FeePerKw)
|
fee := chainfee.SatPerKWeight(msg.FeePerKw)
|
||||||
if err := l.channel.ReceiveUpdateFee(fee); err != nil {
|
if err := l.channel.ReceiveUpdateFee(fee); err != nil {
|
||||||
l.fail(LinkFailureError{code: ErrInvalidUpdate},
|
l.fail(LinkFailureError{code: ErrInvalidUpdate},
|
||||||
"error receiving fee update: %v", err)
|
"error receiving fee update: %v", err)
|
||||||
@ -2394,7 +2395,7 @@ func (l *channelLink) HandleChannelUpdate(message lnwire.Message) {
|
|||||||
|
|
||||||
// updateChannelFee updates the commitment fee-per-kw on this channel by
|
// updateChannelFee updates the commitment fee-per-kw on this channel by
|
||||||
// committing to an update_fee message.
|
// committing to an update_fee message.
|
||||||
func (l *channelLink) updateChannelFee(feePerKw lnwallet.SatPerKWeight) error {
|
func (l *channelLink) updateChannelFee(feePerKw chainfee.SatPerKWeight) error {
|
||||||
|
|
||||||
l.log.Infof("updating commit fee to %v sat/kw", feePerKw)
|
l.log.Infof("updating commit fee to %v sat/kw", feePerKw)
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnpeer"
|
"github.com/lightningnetwork/lnd/lnpeer"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/ticker"
|
"github.com/lightningnetwork/lnd/ticker"
|
||||||
)
|
)
|
||||||
@ -1959,7 +1960,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
|
|||||||
// incoming HTLCs automatically.
|
// incoming HTLCs automatically.
|
||||||
coreLink.cfg.HodlMask = hodl.MaskFromFlags(hodl.ExitSettle)
|
coreLink.cfg.HodlMask = hodl.MaskFromFlags(hodl.ExitSettle)
|
||||||
|
|
||||||
estimator := lnwallet.NewStaticFeeEstimator(6000, 0)
|
estimator := chainfee.NewStaticEstimator(6000, 0)
|
||||||
feePerKw, err := estimator.EstimateFeePerKW(1)
|
feePerKw, err := estimator.EstimateFeePerKW(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to query fee estimator: %v", err)
|
t.Fatalf("unable to query fee estimator: %v", err)
|
||||||
@ -2379,7 +2380,7 @@ func TestChannelLinkBandwidthConsistencyOverflow(t *testing.T) {
|
|||||||
aliceMsgs = coreLink.cfg.Peer.(*mockPeer).sentMsgs
|
aliceMsgs = coreLink.cfg.Peer.(*mockPeer).sentMsgs
|
||||||
)
|
)
|
||||||
|
|
||||||
estimator := lnwallet.NewStaticFeeEstimator(6000, 0)
|
estimator := chainfee.NewStaticEstimator(6000, 0)
|
||||||
feePerKw, err := estimator.EstimateFeePerKW(1)
|
feePerKw, err := estimator.EstimateFeePerKW(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to query fee estimator: %v", err)
|
t.Fatalf("unable to query fee estimator: %v", err)
|
||||||
@ -2630,7 +2631,7 @@ func TestChannelLinkTrimCircuitsPending(t *testing.T) {
|
|||||||
|
|
||||||
// Compute the static fees that will be used to determine the
|
// Compute the static fees that will be used to determine the
|
||||||
// correctness of Alice's bandwidth when forwarding HTLCs.
|
// correctness of Alice's bandwidth when forwarding HTLCs.
|
||||||
estimator := lnwallet.NewStaticFeeEstimator(6000, 0)
|
estimator := chainfee.NewStaticEstimator(6000, 0)
|
||||||
feePerKw, err := estimator.EstimateFeePerKW(1)
|
feePerKw, err := estimator.EstimateFeePerKW(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to query fee estimator: %v", err)
|
t.Fatalf("unable to query fee estimator: %v", err)
|
||||||
@ -2909,7 +2910,7 @@ func TestChannelLinkTrimCircuitsNoCommit(t *testing.T) {
|
|||||||
|
|
||||||
// Compute the static fees that will be used to determine the
|
// Compute the static fees that will be used to determine the
|
||||||
// correctness of Alice's bandwidth when forwarding HTLCs.
|
// correctness of Alice's bandwidth when forwarding HTLCs.
|
||||||
estimator := lnwallet.NewStaticFeeEstimator(6000, 0)
|
estimator := chainfee.NewStaticEstimator(6000, 0)
|
||||||
feePerKw, err := estimator.EstimateFeePerKW(1)
|
feePerKw, err := estimator.EstimateFeePerKW(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to query fee estimator: %v", err)
|
t.Fatalf("unable to query fee estimator: %v", err)
|
||||||
@ -3167,7 +3168,7 @@ func TestChannelLinkBandwidthChanReserve(t *testing.T) {
|
|||||||
aliceMsgs = coreLink.cfg.Peer.(*mockPeer).sentMsgs
|
aliceMsgs = coreLink.cfg.Peer.(*mockPeer).sentMsgs
|
||||||
)
|
)
|
||||||
|
|
||||||
estimator := lnwallet.NewStaticFeeEstimator(6000, 0)
|
estimator := chainfee.NewStaticEstimator(6000, 0)
|
||||||
feePerKw, err := estimator.EstimateFeePerKW(1)
|
feePerKw, err := estimator.EstimateFeePerKW(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to query fee estimator: %v", err)
|
t.Fatalf("unable to query fee estimator: %v", err)
|
||||||
@ -3554,8 +3555,8 @@ func TestChannelRetransmission(t *testing.T) {
|
|||||||
// deviates from our current fee by more 10% or more.
|
// deviates from our current fee by more 10% or more.
|
||||||
func TestShouldAdjustCommitFee(t *testing.T) {
|
func TestShouldAdjustCommitFee(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
netFee lnwallet.SatPerKWeight
|
netFee chainfee.SatPerKWeight
|
||||||
chanFee lnwallet.SatPerKWeight
|
chanFee chainfee.SatPerKWeight
|
||||||
shouldAdjust bool
|
shouldAdjust bool
|
||||||
}{
|
}{
|
||||||
|
|
||||||
@ -3837,7 +3838,7 @@ func TestChannelLinkUpdateCommitFee(t *testing.T) {
|
|||||||
|
|
||||||
// triggerFeeUpdate is a helper closure to determine whether a fee
|
// triggerFeeUpdate is a helper closure to determine whether a fee
|
||||||
// update was triggered and completed properly.
|
// update was triggered and completed properly.
|
||||||
triggerFeeUpdate := func(feeEstimate, newFeeRate lnwallet.SatPerKWeight,
|
triggerFeeUpdate := func(feeEstimate, newFeeRate chainfee.SatPerKWeight,
|
||||||
shouldUpdate bool) {
|
shouldUpdate bool) {
|
||||||
|
|
||||||
t.Helper()
|
t.Helper()
|
||||||
@ -3898,7 +3899,7 @@ func TestChannelLinkUpdateCommitFee(t *testing.T) {
|
|||||||
// Triggering the link to update the fee of the channel with a fee rate
|
// Triggering the link to update the fee of the channel with a fee rate
|
||||||
// that exceeds its maximum fee allocation should result in a fee rate
|
// that exceeds its maximum fee allocation should result in a fee rate
|
||||||
// corresponding to the maximum fee allocation.
|
// corresponding to the maximum fee allocation.
|
||||||
const maxFeeRate lnwallet.SatPerKWeight = 207182320
|
const maxFeeRate chainfee.SatPerKWeight = 207182320
|
||||||
triggerFeeUpdate(maxFeeRate+1, maxFeeRate, true)
|
triggerFeeUpdate(maxFeeRate+1, maxFeeRate, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/invoices"
|
"github.com/lightningnetwork/lnd/invoices"
|
||||||
"github.com/lightningnetwork/lnd/lnpeer"
|
"github.com/lightningnetwork/lnd/lnpeer"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/ticker"
|
"github.com/lightningnetwork/lnd/ticker"
|
||||||
)
|
)
|
||||||
@ -70,13 +70,13 @@ func (m *mockPreimageCache) SubscribeUpdates() *contractcourt.WitnessSubscriptio
|
|||||||
}
|
}
|
||||||
|
|
||||||
type mockFeeEstimator struct {
|
type mockFeeEstimator struct {
|
||||||
byteFeeIn chan lnwallet.SatPerKWeight
|
byteFeeIn chan chainfee.SatPerKWeight
|
||||||
|
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockFeeEstimator) EstimateFeePerKW(
|
func (m *mockFeeEstimator) EstimateFeePerKW(
|
||||||
numBlocks uint32) (lnwallet.SatPerKWeight, error) {
|
numBlocks uint32) (chainfee.SatPerKWeight, error) {
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case feeRate := <-m.byteFeeIn:
|
case feeRate := <-m.byteFeeIn:
|
||||||
@ -86,7 +86,7 @@ func (m *mockFeeEstimator) EstimateFeePerKW(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockFeeEstimator) RelayFeePerKW() lnwallet.SatPerKWeight {
|
func (m *mockFeeEstimator) RelayFeePerKW() chainfee.SatPerKWeight {
|
||||||
return 1e3
|
return 1e3
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ func (m *mockFeeEstimator) Stop() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ lnwallet.FeeEstimator = (*mockFeeEstimator)(nil)
|
var _ chainfee.Estimator = (*mockFeeEstimator)(nil)
|
||||||
|
|
||||||
type mockForwardingLog struct {
|
type mockForwardingLog struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/ticker"
|
"github.com/lightningnetwork/lnd/ticker"
|
||||||
)
|
)
|
||||||
@ -102,7 +103,7 @@ type ChanClose struct {
|
|||||||
// This value is only utilized if the closure type is CloseRegular.
|
// This value is only utilized if the closure type is CloseRegular.
|
||||||
// This will be the starting offered fee when the fee negotiation
|
// This will be the starting offered fee when the fee negotiation
|
||||||
// process for the cooperative closure transaction kicks off.
|
// process for the cooperative closure transaction kicks off.
|
||||||
TargetFeePerKw lnwallet.SatPerKWeight
|
TargetFeePerKw chainfee.SatPerKWeight
|
||||||
|
|
||||||
// Updates is used by request creator to receive the notifications about
|
// Updates is used by request creator to receive the notifications about
|
||||||
// execution of the close channel request.
|
// execution of the close channel request.
|
||||||
@ -1368,7 +1369,7 @@ func (s *Switch) teardownCircuit(pkt *htlcPacket) error {
|
|||||||
// then the last parameter should be the ideal fee-per-kw that will be used as
|
// then the last parameter should be the ideal fee-per-kw that will be used as
|
||||||
// a starting point for close negotiation.
|
// a starting point for close negotiation.
|
||||||
func (s *Switch) CloseLink(chanPoint *wire.OutPoint, closeType ChannelCloseType,
|
func (s *Switch) CloseLink(chanPoint *wire.OutPoint, closeType ChannelCloseType,
|
||||||
targetFeePerKw lnwallet.SatPerKWeight) (chan interface{},
|
targetFeePerKw chainfee.SatPerKWeight) (chan interface{},
|
||||||
chan error) {
|
chan error) {
|
||||||
|
|
||||||
// TODO(roasbeef) abstract out the close updates.
|
// TODO(roasbeef) abstract out the close updates.
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/shachain"
|
"github.com/lightningnetwork/lnd/shachain"
|
||||||
"github.com/lightningnetwork/lnd/ticker"
|
"github.com/lightningnetwork/lnd/ticker"
|
||||||
@ -286,7 +287,7 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte,
|
|||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
estimator := lnwallet.NewStaticFeeEstimator(6000, 0)
|
estimator := chainfee.NewStaticEstimator(6000, 0)
|
||||||
feePerKw, err := estimator.EstimateFeePerKW(1)
|
feePerKw, err := estimator.EstimateFeePerKW(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
@ -1078,7 +1079,7 @@ func newHopNetwork() *hopNetwork {
|
|||||||
obfuscator := NewMockObfuscator()
|
obfuscator := NewMockObfuscator()
|
||||||
|
|
||||||
feeEstimator := &mockFeeEstimator{
|
feeEstimator := &mockFeeEstimator{
|
||||||
byteFeeIn: make(chan lnwallet.SatPerKWeight),
|
byteFeeIn: make(chan chainfee.SatPerKWeight),
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ package walletrpc
|
|||||||
import (
|
import (
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/macaroons"
|
"github.com/lightningnetwork/lnd/macaroons"
|
||||||
"github.com/lightningnetwork/lnd/sweep"
|
"github.com/lightningnetwork/lnd/sweep"
|
||||||
)
|
)
|
||||||
@ -30,7 +31,7 @@ type Config struct {
|
|||||||
|
|
||||||
// FeeEstimator is an instance of the primary fee estimator instance
|
// FeeEstimator is an instance of the primary fee estimator instance
|
||||||
// the WalletKit will use to respond to fee estimation requests.
|
// the WalletKit will use to respond to fee estimation requests.
|
||||||
FeeEstimator lnwallet.FeeEstimator
|
FeeEstimator chainfee.Estimator
|
||||||
|
|
||||||
// Wallet is the primary wallet that the WalletKit will use to proxy
|
// Wallet is the primary wallet that the WalletKit will use to proxy
|
||||||
// any relevant requests to.
|
// any relevant requests to.
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc/signrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/signrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/sweep"
|
"github.com/lightningnetwork/lnd/sweep"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"gopkg.in/macaroon-bakery.v2/bakery"
|
"gopkg.in/macaroon-bakery.v2/bakery"
|
||||||
@ -303,7 +304,7 @@ func (w *WalletKit) SendOutputs(ctx context.Context,
|
|||||||
// Now that we have the outputs mapped, we can request that the wallet
|
// Now that we have the outputs mapped, we can request that the wallet
|
||||||
// attempt to create this transaction.
|
// attempt to create this transaction.
|
||||||
tx, err := w.cfg.Wallet.SendOutputs(
|
tx, err := w.cfg.Wallet.SendOutputs(
|
||||||
outputsToCreate, lnwallet.SatPerKWeight(req.SatPerKw),
|
outputsToCreate, chainfee.SatPerKWeight(req.SatPerKw),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -468,7 +469,7 @@ func (w *WalletKit) BumpFee(ctx context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Construct the request's fee preference.
|
// Construct the request's fee preference.
|
||||||
satPerKw := lnwallet.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
|
satPerKw := chainfee.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
|
||||||
feePreference := sweep.FeePreference{
|
feePreference := sweep.FeePreference{
|
||||||
ConfTarget: uint32(in.TargetConf),
|
ConfTarget: uint32(in.TargetConf),
|
||||||
FeeRate: satPerKw,
|
FeeRate: satPerKw,
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/btcsuite/btcwallet/walletdb"
|
"github.com/btcsuite/btcwallet/walletdb"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -289,7 +290,7 @@ func (b *BtcWallet) IsOurAddress(a btcutil.Address) bool {
|
|||||||
//
|
//
|
||||||
// This is a part of the WalletController interface.
|
// This is a part of the WalletController interface.
|
||||||
func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
|
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
|
// Convert our fee rate from sat/kw to sat/kb since it's required by
|
||||||
// SendOutputs.
|
// SendOutputs.
|
||||||
@ -314,7 +315,7 @@ func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
|
|||||||
//
|
//
|
||||||
// This is a part of the WalletController interface.
|
// This is a part of the WalletController interface.
|
||||||
func (b *BtcWallet) CreateSimpleTx(outputs []*wire.TxOut,
|
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
|
// 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.
|
// this to sat/KB as the CreateSimpleTx method requires this unit.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package lnwallet
|
package chainfee
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -10,85 +10,41 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/blockchain"
|
|
||||||
"github.com/btcsuite/btcd/rpcclient"
|
"github.com/btcsuite/btcd/rpcclient"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
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
|
// 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
|
// because it's the highest number of confs bitcoind will return a fee
|
||||||
// estimate for.
|
// estimate for.
|
||||||
maxBlockTarget uint32 = 1009
|
maxBlockTarget uint32 = 1009
|
||||||
|
|
||||||
// minBlockTarget is the lowest number of blocks confirmations that
|
// 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.
|
// less than this will result in an error.
|
||||||
minBlockTarget uint32 = 2
|
minBlockTarget uint32 = 2
|
||||||
|
|
||||||
// minFeeUpdateTimeout represents the minimum interval in which a
|
// 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
|
minFeeUpdateTimeout = 5 * time.Minute
|
||||||
|
|
||||||
// maxFeeUpdateTimeout represents the maximum interval in which a
|
// 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
|
maxFeeUpdateTimeout = 20 * time.Minute
|
||||||
)
|
)
|
||||||
|
|
||||||
// SatPerKVByte represents a fee rate in sat/kb.
|
// Estimator provides the ability to estimate on-chain transaction fees for
|
||||||
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
|
|
||||||
// various combinations of transaction sizes and desired confirmation time
|
// various combinations of transaction sizes and desired confirmation time
|
||||||
// (measured by number of blocks).
|
// (measured by number of blocks).
|
||||||
type FeeEstimator interface {
|
type Estimator interface {
|
||||||
// EstimateFeePerKW takes in a target for the number of blocks until an
|
// EstimateFeePerKW takes in a target for the number of blocks until an
|
||||||
// initial confirmation and returns the estimated fee expressed in
|
// initial confirmation and returns the estimated fee expressed in
|
||||||
// sat/kw.
|
// sat/kw.
|
||||||
EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error)
|
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.
|
// it needs to perform its duty.
|
||||||
Start() error
|
Start() error
|
||||||
|
|
||||||
@ -102,11 +58,11 @@ type FeeEstimator interface {
|
|||||||
RelayFeePerKW() SatPerKWeight
|
RelayFeePerKW() SatPerKWeight
|
||||||
}
|
}
|
||||||
|
|
||||||
// StaticFeeEstimator will return a static value for all fee calculation
|
// StaticEstimator will return a static value for all fee calculation requests.
|
||||||
// requests. It is designed to be replaced by a proper fee calculation
|
// It is designed to be replaced by a proper fee calculation implementation.
|
||||||
// implementation. The fees are not accessible directly, because changing them
|
// The fees are not accessible directly, because changing them would not be
|
||||||
// would not be thread safe.
|
// thread safe.
|
||||||
type StaticFeeEstimator struct {
|
type StaticEstimator struct {
|
||||||
// feePerKW 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.
|
// returned by this fee estimator.
|
||||||
feePerKW SatPerKWeight
|
feePerKW SatPerKWeight
|
||||||
@ -116,11 +72,10 @@ type StaticFeeEstimator struct {
|
|||||||
relayFee SatPerKWeight
|
relayFee SatPerKWeight
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStaticFeeEstimator returns a new static fee estimator instance.
|
// NewStaticEstimator returns a new static fee estimator instance.
|
||||||
func NewStaticFeeEstimator(feePerKW,
|
func NewStaticEstimator(feePerKW, relayFee SatPerKWeight) *StaticEstimator {
|
||||||
relayFee SatPerKWeight) *StaticFeeEstimator {
|
|
||||||
|
|
||||||
return &StaticFeeEstimator{
|
return &StaticEstimator{
|
||||||
feePerKW: feePerKW,
|
feePerKW: feePerKW,
|
||||||
relayFee: relayFee,
|
relayFee: relayFee,
|
||||||
}
|
}
|
||||||
@ -128,43 +83,43 @@ func NewStaticFeeEstimator(feePerKW,
|
|||||||
|
|
||||||
// EstimateFeePerKW 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.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (e StaticFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
|
func (e StaticEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
|
||||||
return e.feePerKW, nil
|
return e.feePerKW, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RelayFeePerKW returns the minimum fee rate required for transactions to be
|
// RelayFeePerKW returns the minimum fee rate required for transactions to be
|
||||||
// relayed.
|
// relayed.
|
||||||
//
|
//
|
||||||
// NOTE: This method is part of the FeeEstimator interface.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (e StaticFeeEstimator) RelayFeePerKW() SatPerKWeight {
|
func (e StaticEstimator) RelayFeePerKW() SatPerKWeight {
|
||||||
return e.relayFee
|
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.
|
// it needs to perform its duty.
|
||||||
//
|
//
|
||||||
// NOTE: This method is part of the FeeEstimator interface.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (e StaticFeeEstimator) Start() error {
|
func (e StaticEstimator) Start() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop stops any spawned goroutines and cleans up the resources used
|
// Stop stops any spawned goroutines and cleans up the resources used
|
||||||
// by the fee estimator.
|
// by the fee estimator.
|
||||||
//
|
//
|
||||||
// NOTE: This method is part of the FeeEstimator interface.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (e StaticFeeEstimator) Stop() error {
|
func (e StaticEstimator) Stop() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// A compile-time assertion to ensure that StaticFeeEstimator implements the
|
// A compile-time assertion to ensure that StaticFeeEstimator implements the
|
||||||
// FeeEstimator interface.
|
// Estimator interface.
|
||||||
var _ FeeEstimator = (*StaticFeeEstimator)(nil)
|
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
|
// by the RPC interface of an active btcd node. This implementation will proxy
|
||||||
// any fee estimation requests to btcd's RPC interface.
|
// 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
|
// 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
|
// if the fee estimator does not yet have enough data to actually
|
||||||
// produce fee estimates.
|
// produce fee estimates.
|
||||||
@ -179,13 +134,13 @@ type BtcdFeeEstimator struct {
|
|||||||
btcdConn *rpcclient.Client
|
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
|
// 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
|
// 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
|
// the occasion that the estimator has insufficient data, or returns zero for a
|
||||||
// fee estimate.
|
// fee estimate.
|
||||||
func NewBtcdFeeEstimator(rpcConfig rpcclient.ConnConfig,
|
func NewBtcdEstimator(rpcConfig rpcclient.ConnConfig,
|
||||||
fallBackFeeRate SatPerKWeight) (*BtcdFeeEstimator, error) {
|
fallBackFeeRate SatPerKWeight) (*BtcdEstimator, error) {
|
||||||
|
|
||||||
rpcConfig.DisableConnectOnNew = true
|
rpcConfig.DisableConnectOnNew = true
|
||||||
rpcConfig.DisableAutoReconnect = false
|
rpcConfig.DisableAutoReconnect = false
|
||||||
@ -194,17 +149,17 @@ func NewBtcdFeeEstimator(rpcConfig rpcclient.ConnConfig,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &BtcdFeeEstimator{
|
return &BtcdEstimator{
|
||||||
fallbackFeePerKW: fallBackFeeRate,
|
fallbackFeePerKW: fallBackFeeRate,
|
||||||
btcdConn: chainConn,
|
btcdConn: chainConn,
|
||||||
}, nil
|
}, 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.
|
// it needs to perform its duty.
|
||||||
//
|
//
|
||||||
// NOTE: This method is part of the FeeEstimator interface.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (b *BtcdFeeEstimator) Start() error {
|
func (b *BtcdEstimator) Start() error {
|
||||||
if err := b.btcdConn.Connect(20); err != nil {
|
if err := b.btcdConn.Connect(20); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -233,7 +188,7 @@ func (b *BtcdFeeEstimator) Start() error {
|
|||||||
b.minFeePerKW = FeePerKwFloor
|
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))
|
int64(b.minFeePerKW))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -242,8 +197,8 @@ func (b *BtcdFeeEstimator) Start() error {
|
|||||||
// Stop stops any spawned goroutines and cleans up the resources used
|
// Stop stops any spawned goroutines and cleans up the resources used
|
||||||
// by the fee estimator.
|
// by the fee estimator.
|
||||||
//
|
//
|
||||||
// NOTE: This method is part of the FeeEstimator interface.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (b *BtcdFeeEstimator) Stop() error {
|
func (b *BtcdEstimator) Stop() error {
|
||||||
b.btcdConn.Shutdown()
|
b.btcdConn.Shutdown()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -252,15 +207,15 @@ func (b *BtcdFeeEstimator) Stop() error {
|
|||||||
// EstimateFeePerKW takes in a target for the number of blocks until an initial
|
// EstimateFeePerKW takes in a target for the number of blocks until an initial
|
||||||
// confirmation and returns the estimated fee expressed in sat/kw.
|
// confirmation and returns the estimated fee expressed in sat/kw.
|
||||||
//
|
//
|
||||||
// NOTE: This method is part of the FeeEstimator interface.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (b *BtcdFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
|
func (b *BtcdEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
|
||||||
feeEstimate, err := b.fetchEstimate(numBlocks)
|
feeEstimate, err := b.fetchEstimate(numBlocks)
|
||||||
switch {
|
switch {
|
||||||
// If the estimator doesn't have enough data, or returns an error, then
|
// 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
|
// to return a proper value, then we'll return the default fall back
|
||||||
// fee rate.
|
// fee rate.
|
||||||
case err != nil:
|
case err != nil:
|
||||||
walletLog.Errorf("unable to query estimator: %v", err)
|
log.Errorf("unable to query estimator: %v", err)
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
||||||
case feeEstimate == 0:
|
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
|
// RelayFeePerKW returns the minimum fee rate required for transactions to be
|
||||||
// relayed.
|
// relayed.
|
||||||
//
|
//
|
||||||
// NOTE: This method is part of the FeeEstimator interface.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (b *BtcdFeeEstimator) RelayFeePerKW() SatPerKWeight {
|
func (b *BtcdEstimator) RelayFeePerKW() SatPerKWeight {
|
||||||
return b.minFeePerKW
|
return b.minFeePerKW
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchEstimate returns a fee estimate for a transaction to be confirmed in
|
// fetchEstimate returns a fee estimate for a transaction to be confirmed in
|
||||||
// confTarget blocks. The estimate is returned in sat/kw.
|
// 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.
|
// First, we'll fetch the estimate for our confirmation target.
|
||||||
btcPerKB, err := b.btcdConn.EstimateFee(int64(confTarget))
|
btcPerKB, err := b.btcdConn.EstimateFee(int64(confTarget))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -300,26 +255,26 @@ func (b *BtcdFeeEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight, erro
|
|||||||
|
|
||||||
// Finally, we'll enforce our fee floor.
|
// Finally, we'll enforce our fee floor.
|
||||||
if satPerKw < b.minFeePerKW {
|
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,
|
"using fee floor of %v sat/kw instead", satPerKw,
|
||||||
b.minFeePerKW)
|
b.minFeePerKW)
|
||||||
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)
|
int64(satPerKw), confTarget)
|
||||||
|
|
||||||
return satPerKw, nil
|
return satPerKw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// A compile-time assertion to ensure that BtcdFeeEstimator implements the
|
// A compile-time assertion to ensure that BtcdEstimator implements the
|
||||||
// FeeEstimator interface.
|
// Estimator interface.
|
||||||
var _ FeeEstimator = (*BtcdFeeEstimator)(nil)
|
var _ Estimator = (*BtcdEstimator)(nil)
|
||||||
|
|
||||||
// BitcoindFeeEstimator is an implementation of the FeeEstimator interface
|
// BitcoindEstimator is an implementation of the Estimator interface backed by
|
||||||
// backed by the RPC interface of an active bitcoind node. This implementation
|
// the RPC interface of an active bitcoind node. This implementation will proxy
|
||||||
// will proxy any fee estimation requests to bitcoind's RPC interface.
|
// any fee estimation requests to bitcoind's RPC interface.
|
||||||
type BitcoindFeeEstimator struct {
|
type BitcoindEstimator struct {
|
||||||
// fallbackFeePerKW is the fallback fee rate in sat/kw that is returned
|
// fallbackFeePerKW is the fallback fee rate in sat/kw that is returned
|
||||||
// if the fee estimator does not yet have enough data to actually
|
// if the fee estimator does not yet have enough data to actually
|
||||||
// produce fee estimates.
|
// produce fee estimates.
|
||||||
@ -334,13 +289,13 @@ type BitcoindFeeEstimator struct {
|
|||||||
bitcoindConn *rpcclient.Client
|
bitcoindConn *rpcclient.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBitcoindFeeEstimator creates a new BitcoindFeeEstimator given a fully
|
// NewBitcoindEstimator creates a new BitcoindEstimator given a fully populated
|
||||||
// populated rpc config that is able to successfully connect and authenticate
|
// rpc config that is able to successfully connect and authenticate with the
|
||||||
// with the bitcoind node, and also a fall back fee rate. The fallback fee rate
|
// bitcoind node, and also a fall back fee rate. The fallback fee rate is used
|
||||||
// is used in the occasion that the estimator has insufficient data, or returns
|
// in the occasion that the estimator has insufficient data, or returns zero
|
||||||
// zero for a fee estimate.
|
// for a fee estimate.
|
||||||
func NewBitcoindFeeEstimator(rpcConfig rpcclient.ConnConfig,
|
func NewBitcoindEstimator(rpcConfig rpcclient.ConnConfig,
|
||||||
fallBackFeeRate SatPerKWeight) (*BitcoindFeeEstimator, error) {
|
fallBackFeeRate SatPerKWeight) (*BitcoindEstimator, error) {
|
||||||
|
|
||||||
rpcConfig.DisableConnectOnNew = true
|
rpcConfig.DisableConnectOnNew = true
|
||||||
rpcConfig.DisableAutoReconnect = false
|
rpcConfig.DisableAutoReconnect = false
|
||||||
@ -351,17 +306,17 @@ func NewBitcoindFeeEstimator(rpcConfig rpcclient.ConnConfig,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &BitcoindFeeEstimator{
|
return &BitcoindEstimator{
|
||||||
fallbackFeePerKW: fallBackFeeRate,
|
fallbackFeePerKW: fallBackFeeRate,
|
||||||
bitcoindConn: chainConn,
|
bitcoindConn: chainConn,
|
||||||
}, nil
|
}, 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.
|
// it needs to perform its duty.
|
||||||
//
|
//
|
||||||
// NOTE: This method is part of the FeeEstimator interface.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (b *BitcoindFeeEstimator) Start() error {
|
func (b *BitcoindEstimator) Start() error {
|
||||||
// Once the connection to the backend node has been established, we'll
|
// 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
|
// query it for its minimum relay fee. Since the `getinfo` RPC has been
|
||||||
// deprecated for `bitcoind`, we'll need to send a `getnetworkinfo`
|
// deprecated for `bitcoind`, we'll need to send a `getnetworkinfo`
|
||||||
@ -396,7 +351,7 @@ func (b *BitcoindFeeEstimator) Start() error {
|
|||||||
b.minFeePerKW = FeePerKwFloor
|
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))
|
int64(b.minFeePerKW))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -405,23 +360,23 @@ func (b *BitcoindFeeEstimator) Start() error {
|
|||||||
// Stop stops any spawned goroutines and cleans up the resources used
|
// Stop stops any spawned goroutines and cleans up the resources used
|
||||||
// by the fee estimator.
|
// by the fee estimator.
|
||||||
//
|
//
|
||||||
// NOTE: This method is part of the FeeEstimator interface.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (b *BitcoindFeeEstimator) Stop() error {
|
func (b *BitcoindEstimator) Stop() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EstimateFeePerKW takes in a target for the number of blocks until an initial
|
// EstimateFeePerKW takes in a target for the number of blocks until an initial
|
||||||
// confirmation and returns the estimated fee expressed in sat/kw.
|
// confirmation and returns the estimated fee expressed in sat/kw.
|
||||||
//
|
//
|
||||||
// NOTE: This method is part of the FeeEstimator interface.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (b *BitcoindFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
|
func (b *BitcoindEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
|
||||||
feeEstimate, err := b.fetchEstimate(numBlocks)
|
feeEstimate, err := b.fetchEstimate(numBlocks)
|
||||||
switch {
|
switch {
|
||||||
// If the estimator doesn't have enough data, or returns an error, then
|
// 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
|
// to return a proper value, then we'll return the default fall back
|
||||||
// fee rate.
|
// fee rate.
|
||||||
case err != nil:
|
case err != nil:
|
||||||
walletLog.Errorf("unable to query estimator: %v", err)
|
log.Errorf("unable to query estimator: %v", err)
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
||||||
case feeEstimate == 0:
|
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
|
// RelayFeePerKW returns the minimum fee rate required for transactions to be
|
||||||
// relayed.
|
// relayed.
|
||||||
//
|
//
|
||||||
// NOTE: This method is part of the FeeEstimator interface.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (b *BitcoindFeeEstimator) RelayFeePerKW() SatPerKWeight {
|
func (b *BitcoindEstimator) RelayFeePerKW() SatPerKWeight {
|
||||||
return b.minFeePerKW
|
return b.minFeePerKW
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchEstimate returns a fee estimate for a transaction to be confirmed in
|
// fetchEstimate returns a fee estimate for a transaction to be confirmed in
|
||||||
// confTarget blocks. The estimate is returned in sat/kw.
|
// 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,
|
// First, we'll send an "estimatesmartfee" command as a raw request,
|
||||||
// since it isn't supported by btcd but is available in bitcoind.
|
// since it isn't supported by btcd but is available in bitcoind.
|
||||||
target, err := json.Marshal(uint64(confTarget))
|
target, err := json.Marshal(uint64(confTarget))
|
||||||
@ -478,26 +433,26 @@ func (b *BitcoindFeeEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight,
|
|||||||
|
|
||||||
// Finally, we'll enforce our fee floor.
|
// Finally, we'll enforce our fee floor.
|
||||||
if satPerKw < b.minFeePerKW {
|
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,
|
"using fee floor of %v sat/kw instead", satPerKw,
|
||||||
b.minFeePerKW)
|
b.minFeePerKW)
|
||||||
|
|
||||||
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)
|
int64(satPerKw), confTarget)
|
||||||
|
|
||||||
return satPerKw, nil
|
return satPerKw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// A compile-time assertion to ensure that BitcoindFeeEstimator implements the
|
// A compile-time assertion to ensure that BitcoindEstimator implements the
|
||||||
// FeeEstimator interface.
|
// Estimator interface.
|
||||||
var _ FeeEstimator = (*BitcoindFeeEstimator)(nil)
|
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
|
// 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.
|
// be fully generic in its logic.
|
||||||
type WebAPIFeeSource interface {
|
type WebAPIFeeSource interface {
|
||||||
// GenQueryURL generates the full query URL. The value returned by this
|
// 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.
|
// WebAPIFeeSource interface.
|
||||||
var _ WebAPIFeeSource = (*SparseConfFeeSource)(nil)
|
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.
|
// queries an HTTP-based fee estimation from an existing web API.
|
||||||
type WebAPIFeeEstimator struct {
|
type WebAPIEstimator struct {
|
||||||
started sync.Once
|
started sync.Once
|
||||||
stopped sync.Once
|
stopped sync.Once
|
||||||
|
|
||||||
@ -581,12 +536,12 @@ type WebAPIFeeEstimator struct {
|
|||||||
wg sync.WaitGroup
|
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.
|
// fallback default fee. The fees are updated whenever a new block is mined.
|
||||||
func NewWebAPIFeeEstimator(
|
func NewWebAPIEstimator(
|
||||||
api WebAPIFeeSource, defaultFee SatPerKWeight) *WebAPIFeeEstimator {
|
api WebAPIFeeSource, defaultFee SatPerKWeight) *WebAPIEstimator {
|
||||||
|
|
||||||
return &WebAPIFeeEstimator{
|
return &WebAPIEstimator{
|
||||||
apiSource: api,
|
apiSource: api,
|
||||||
feeByBlockTarget: make(map[uint32]uint32),
|
feeByBlockTarget: make(map[uint32]uint32),
|
||||||
defaultFeePerKw: defaultFee,
|
defaultFeePerKw: defaultFee,
|
||||||
@ -597,8 +552,8 @@ func NewWebAPIFeeEstimator(
|
|||||||
// EstimateFeePerKW takes in a target for the number of blocks until an initial
|
// EstimateFeePerKW takes in a target for the number of blocks until an initial
|
||||||
// confirmation and returns the estimated fee expressed in sat/kw.
|
// confirmation and returns the estimated fee expressed in sat/kw.
|
||||||
//
|
//
|
||||||
// NOTE: This method is part of the FeeEstimator interface.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (w *WebAPIFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
|
func (w *WebAPIEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
|
||||||
if numBlocks > maxBlockTarget {
|
if numBlocks > maxBlockTarget {
|
||||||
numBlocks = maxBlockTarget
|
numBlocks = maxBlockTarget
|
||||||
} else if numBlocks < minBlockTarget {
|
} else if numBlocks < minBlockTarget {
|
||||||
@ -618,20 +573,20 @@ func (w *WebAPIFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight,
|
|||||||
satPerKw = FeePerKwFloor
|
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)
|
int64(satPerKw), numBlocks)
|
||||||
|
|
||||||
return satPerKw, nil
|
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.
|
// to perform its duty.
|
||||||
//
|
//
|
||||||
// NOTE: This method is part of the FeeEstimator interface.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (w *WebAPIFeeEstimator) Start() error {
|
func (w *WebAPIEstimator) Start() error {
|
||||||
var err error
|
var err error
|
||||||
w.started.Do(func() {
|
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.updateFeeTicker = time.NewTicker(w.randomFeeUpdateTimeout())
|
||||||
w.updateFeeEstimates()
|
w.updateFeeEstimates()
|
||||||
@ -646,10 +601,10 @@ func (w *WebAPIFeeEstimator) Start() error {
|
|||||||
// Stop stops any spawned goroutines and cleans up the resources used by the
|
// Stop stops any spawned goroutines and cleans up the resources used by the
|
||||||
// fee estimator.
|
// fee estimator.
|
||||||
//
|
//
|
||||||
// NOTE: This method is part of the FeeEstimator interface.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (w *WebAPIFeeEstimator) Stop() error {
|
func (w *WebAPIEstimator) Stop() error {
|
||||||
w.stopped.Do(func() {
|
w.stopped.Do(func() {
|
||||||
walletLog.Infof("Stopping web API fee estimator")
|
log.Infof("Stopping web API fee estimator")
|
||||||
|
|
||||||
w.updateFeeTicker.Stop()
|
w.updateFeeTicker.Stop()
|
||||||
|
|
||||||
@ -662,15 +617,15 @@ func (w *WebAPIFeeEstimator) Stop() error {
|
|||||||
// RelayFeePerKW returns the minimum fee rate required for transactions to be
|
// RelayFeePerKW returns the minimum fee rate required for transactions to be
|
||||||
// relayed.
|
// relayed.
|
||||||
//
|
//
|
||||||
// NOTE: This method is part of the FeeEstimator interface.
|
// NOTE: This method is part of the Estimator interface.
|
||||||
func (w *WebAPIFeeEstimator) RelayFeePerKW() SatPerKWeight {
|
func (w *WebAPIEstimator) RelayFeePerKW() SatPerKWeight {
|
||||||
return FeePerKwFloor
|
return FeePerKwFloor
|
||||||
}
|
}
|
||||||
|
|
||||||
// randomFeeUpdateTimeout returns a random timeout between minFeeUpdateTimeout
|
// randomFeeUpdateTimeout returns a random timeout between minFeeUpdateTimeout
|
||||||
// and maxFeeUpdateTimeout that will be used to determine how often the Estimator
|
// and maxFeeUpdateTimeout that will be used to determine how often the Estimator
|
||||||
// should retrieve fresh fees from its API.
|
// should retrieve fresh fees from its API.
|
||||||
func (w *WebAPIFeeEstimator) randomFeeUpdateTimeout() time.Duration {
|
func (w *WebAPIEstimator) randomFeeUpdateTimeout() time.Duration {
|
||||||
lower := int64(minFeeUpdateTimeout)
|
lower := int64(minFeeUpdateTimeout)
|
||||||
upper := int64(maxFeeUpdateTimeout)
|
upper := int64(maxFeeUpdateTimeout)
|
||||||
return time.Duration(prand.Int63n(upper-lower) + lower)
|
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
|
// 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
|
// confirmation and returns an estimated fee (if one was returned by the API). If
|
||||||
// the fee was not previously cached, we cache it here.
|
// 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()
|
w.feesMtx.Lock()
|
||||||
defer w.feesMtx.Unlock()
|
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.
|
// 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
|
// 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
|
// 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
|
// response from the service. This way, if the service is down or
|
||||||
@ -725,7 +680,7 @@ func (w *WebAPIFeeEstimator) updateFeeEstimates() {
|
|||||||
targetURL := w.apiSource.GenQueryURL()
|
targetURL := w.apiSource.GenQueryURL()
|
||||||
resp, err := netClient.Get(targetURL)
|
resp, err := netClient.Get(targetURL)
|
||||||
if err != nil {
|
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)
|
err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -735,7 +690,7 @@ func (w *WebAPIFeeEstimator) updateFeeEstimates() {
|
|||||||
// to parse out the body to obtain our final result.
|
// to parse out the body to obtain our final result.
|
||||||
feesByBlockTarget, err := w.apiSource.ParseResponse(resp.Body)
|
feesByBlockTarget, err := w.apiSource.ParseResponse(resp.Body)
|
||||||
if err != nil {
|
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)
|
err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -746,7 +701,7 @@ func (w *WebAPIFeeEstimator) updateFeeEstimates() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// feeUpdateManager updates the fee estimates whenever a new block comes in.
|
// feeUpdateManager updates the fee estimates whenever a new block comes in.
|
||||||
func (w *WebAPIFeeEstimator) feeUpdateManager() {
|
func (w *WebAPIEstimator) feeUpdateManager() {
|
||||||
defer w.wg.Done()
|
defer w.wg.Done()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -759,6 +714,6 @@ func (w *WebAPIFeeEstimator) feeUpdateManager() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A compile-time assertion to ensure that WebAPIFeeEstimator implements the
|
// A compile-time assertion to ensure that WebAPIEstimator implements the
|
||||||
// FeeEstimator interface.
|
// Estimator interface.
|
||||||
var _ FeeEstimator = (*WebAPIFeeEstimator)(nil)
|
var _ Estimator = (*WebAPIEstimator)(nil)
|
@ -1,4 +1,4 @@
|
|||||||
package lnwallet_test
|
package chainfee
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -9,8 +9,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockSparseConfFeeSource struct {
|
type mockSparseConfFeeSource struct {
|
||||||
@ -38,9 +36,9 @@ func TestFeeRateTypes(t *testing.T) {
|
|||||||
const weight = vsize * 4
|
const weight = vsize * 4
|
||||||
|
|
||||||
// Test the conversion from sat/kw to sat/kb.
|
// 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()
|
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 "+
|
t.Fatalf("expected %d sat/kb, got %d sat/kb when "+
|
||||||
"converting from %d sat/kw", feePerKw*4,
|
"converting from %d sat/kw", feePerKw*4,
|
||||||
feePerKB, feePerKw)
|
feePerKB, feePerKw)
|
||||||
@ -62,9 +60,9 @@ func TestFeeRateTypes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test the conversion from sat/kb to sat/kw.
|
// 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()
|
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 "+
|
t.Fatalf("expected %d sat/kw, got %d sat/kw when "+
|
||||||
"converting from %d sat/kb", feePerKB/4,
|
"converting from %d sat/kb", feePerKB/4,
|
||||||
feePerKw, feePerKB)
|
feePerKw, feePerKB)
|
||||||
@ -91,9 +89,9 @@ func TestFeeRateTypes(t *testing.T) {
|
|||||||
func TestStaticFeeEstimator(t *testing.T) {
|
func TestStaticFeeEstimator(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
const feePerKw = lnwallet.FeePerKwFloor
|
const feePerKw = FeePerKwFloor
|
||||||
|
|
||||||
feeEstimator := lnwallet.NewStaticFeeEstimator(feePerKw, 0)
|
feeEstimator := NewStaticEstimator(feePerKw, 0)
|
||||||
if err := feeEstimator.Start(); err != nil {
|
if err := feeEstimator.Start(); err != nil {
|
||||||
t.Fatalf("unable to start fee estimator: %v", err)
|
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.
|
// Test that GenQueryURL returns the URL as is.
|
||||||
url := "test"
|
url := "test"
|
||||||
feeSource := lnwallet.SparseConfFeeSource{URL: url}
|
feeSource := SparseConfFeeSource{URL: url}
|
||||||
queryURL := feeSource.GenQueryURL()
|
queryURL := feeSource.GenQueryURL()
|
||||||
if queryURL != url {
|
if queryURL != url {
|
||||||
t.Fatalf("expected query URL of %v, got %v", url, queryURL)
|
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) {
|
func TestWebAPIFeeEstimator(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
feeFloor := uint32(lnwallet.FeePerKwFloor.FeePerKVByte())
|
feeFloor := uint32(FeePerKwFloor.FeePerKVByte())
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
target uint32
|
target uint32
|
||||||
@ -194,7 +192,7 @@ func TestWebAPIFeeEstimator(t *testing.T) {
|
|||||||
fees: testFees,
|
fees: testFees,
|
||||||
}
|
}
|
||||||
|
|
||||||
estimator := lnwallet.NewWebAPIFeeEstimator(feeSource, 10)
|
estimator := NewWebAPIEstimator(feeSource, 10)
|
||||||
|
|
||||||
// Test that requesting a fee when no fees have been cached fails.
|
// Test that requesting a fee when no fees have been cached fails.
|
||||||
_, err := estimator.EstimateFeePerKW(5)
|
_, err := estimator.EstimateFeePerKW(5)
|
||||||
@ -210,6 +208,7 @@ func TestWebAPIFeeEstimator(t *testing.T) {
|
|||||||
defer estimator.Stop()
|
defer estimator.Stop()
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
tc := tc
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
est, err := estimator.EstimateFeePerKW(tc.target)
|
est, err := estimator.EstimateFeePerKW(tc.target)
|
||||||
if tc.err != "" {
|
if tc.err != "" {
|
||||||
@ -220,7 +219,7 @@ func TestWebAPIFeeEstimator(t *testing.T) {
|
|||||||
"fail, instead got: %v", err)
|
"fail, instead got: %v", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
exp := lnwallet.SatPerKVByte(tc.est).FeePerKWeight()
|
exp := SatPerKVByte(tc.est).FeePerKWeight()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to estimate fee for "+
|
t.Fatalf("unable to estimate fee for "+
|
||||||
"%v block target, got: %v",
|
"%v block target, got: %v",
|
29
lnwallet/chainfee/log.go
Normal file
29
lnwallet/chainfee/log.go
Normal 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
lnwallet/chainfee/rates.go
Normal file
53
lnwallet/chainfee/rates.go
Normal 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))
|
||||||
|
}
|
@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -512,7 +513,7 @@ type commitment struct {
|
|||||||
|
|
||||||
// feePerKw is the fee per kw used to calculate this commitment
|
// feePerKw is the fee per kw used to calculate this commitment
|
||||||
// transaction's fee.
|
// transaction's fee.
|
||||||
feePerKw SatPerKWeight
|
feePerKw chainfee.SatPerKWeight
|
||||||
|
|
||||||
// dustLimit is the limit on the commitment transaction such that no
|
// dustLimit is the limit on the commitment transaction such that no
|
||||||
// output values should be below this amount.
|
// 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
|
// 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
|
// restore commitment state written do disk back into memory once we need to
|
||||||
// restart a channel session.
|
// restart a channel session.
|
||||||
func (lc *LightningChannel) diskHtlcToPayDesc(feeRate SatPerKWeight,
|
func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight,
|
||||||
commitHeight uint64, htlc *channeldb.HTLC, localCommitKeys,
|
commitHeight uint64, htlc *channeldb.HTLC, localCommitKeys,
|
||||||
remoteCommitKeys *CommitmentKeyRing) (PaymentDescriptor, error) {
|
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
|
// these payment descriptors can be re-inserted into the in-memory updateLog
|
||||||
// for each side.
|
// for each side.
|
||||||
func (lc *LightningChannel) extractPayDescs(commitHeight uint64,
|
func (lc *LightningChannel) extractPayDescs(commitHeight uint64,
|
||||||
feeRate SatPerKWeight, htlcs []channeldb.HTLC, localCommitKeys,
|
feeRate chainfee.SatPerKWeight, htlcs []channeldb.HTLC, localCommitKeys,
|
||||||
remoteCommitKeys *CommitmentKeyRing) ([]PaymentDescriptor, []PaymentDescriptor, error) {
|
remoteCommitKeys *CommitmentKeyRing) ([]PaymentDescriptor, []PaymentDescriptor, error) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -894,7 +895,8 @@ func (lc *LightningChannel) diskCommitToMemCommit(isLocal bool,
|
|||||||
// HTLC"s into PaymentDescriptor's so we can re-insert them into our
|
// HTLC"s into PaymentDescriptor's so we can re-insert them into our
|
||||||
// update log.
|
// update log.
|
||||||
incomingHtlcs, outgoingHtlcs, err := lc.extractPayDescs(
|
incomingHtlcs, outgoingHtlcs, err := lc.extractPayDescs(
|
||||||
diskCommit.CommitHeight, SatPerKWeight(diskCommit.FeePerKw),
|
diskCommit.CommitHeight,
|
||||||
|
chainfee.SatPerKWeight(diskCommit.FeePerKw),
|
||||||
diskCommit.Htlcs, localCommitKeys, remoteCommitKeys,
|
diskCommit.Htlcs, localCommitKeys, remoteCommitKeys,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -915,7 +917,7 @@ func (lc *LightningChannel) diskCommitToMemCommit(isLocal bool,
|
|||||||
txn: diskCommit.CommitTx,
|
txn: diskCommit.CommitTx,
|
||||||
sig: diskCommit.CommitSig,
|
sig: diskCommit.CommitSig,
|
||||||
fee: diskCommit.CommitFee,
|
fee: diskCommit.CommitFee,
|
||||||
feePerKw: SatPerKWeight(diskCommit.FeePerKw),
|
feePerKw: chainfee.SatPerKWeight(diskCommit.FeePerKw),
|
||||||
incomingHTLCs: incomingHtlcs,
|
incomingHTLCs: incomingHtlcs,
|
||||||
outgoingHTLCs: outgoingHtlcs,
|
outgoingHTLCs: outgoingHtlcs,
|
||||||
}
|
}
|
||||||
@ -1509,7 +1511,7 @@ func (lc *LightningChannel) ResetState() {
|
|||||||
// if nothing happened.
|
// if nothing happened.
|
||||||
func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate,
|
func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate,
|
||||||
remoteUpdateLog *updateLog, commitHeight uint64,
|
remoteUpdateLog *updateLog, commitHeight uint64,
|
||||||
feeRate SatPerKWeight, remoteCommitKeys *CommitmentKeyRing,
|
feeRate chainfee.SatPerKWeight, remoteCommitKeys *CommitmentKeyRing,
|
||||||
remoteDustLimit btcutil.Amount) (*PaymentDescriptor, error) {
|
remoteDustLimit btcutil.Amount) (*PaymentDescriptor, error) {
|
||||||
|
|
||||||
// Depending on the type of update message we'll map that to a distinct
|
// 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 {
|
for _, logUpdate := range pendingRemoteCommitDiff.LogUpdates {
|
||||||
payDesc, err := lc.logUpdateToPayDesc(
|
payDesc, err := lc.logUpdateToPayDesc(
|
||||||
&logUpdate, lc.remoteUpdateLog, pendingHeight,
|
&logUpdate, lc.remoteUpdateLog, pendingHeight,
|
||||||
SatPerKWeight(pendingCommit.FeePerKw), pendingRemoteKeys,
|
chainfee.SatPerKWeight(pendingCommit.FeePerKw),
|
||||||
|
pendingRemoteKeys,
|
||||||
lc.channelState.RemoteChanCfg.DustLimit,
|
lc.channelState.RemoteChanCfg.DustLimit,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2109,7 +2112,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
|||||||
// an output on the commitment transaction.
|
// an output on the commitment transaction.
|
||||||
if htlcIsDust(
|
if htlcIsDust(
|
||||||
htlc.Incoming, false,
|
htlc.Incoming, false,
|
||||||
SatPerKWeight(revokedSnapshot.FeePerKw),
|
chainfee.SatPerKWeight(revokedSnapshot.FeePerKw),
|
||||||
htlc.Amt.ToSatoshis(), chanState.RemoteChanCfg.DustLimit,
|
htlc.Amt.ToSatoshis(), chanState.RemoteChanCfg.DustLimit,
|
||||||
) {
|
) {
|
||||||
continue
|
continue
|
||||||
@ -2198,13 +2201,13 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
|||||||
|
|
||||||
// htlcTimeoutFee returns the fee in satoshis required for an HTLC timeout
|
// htlcTimeoutFee returns the fee in satoshis required for an HTLC timeout
|
||||||
// transaction based on the current fee rate.
|
// 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)
|
return feePerKw.FeeForWeight(input.HtlcTimeoutWeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
// htlcSuccessFee returns the fee in satoshis required for an HTLC success
|
// htlcSuccessFee returns the fee in satoshis required for an HTLC success
|
||||||
// transaction based on the current fee rate.
|
// 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)
|
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
|
// 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
|
// covenants. Depending on the two bits, we'll either be using a timeout or
|
||||||
// success transaction which have different weights.
|
// 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 {
|
htlcAmt, dustLimit btcutil.Amount) bool {
|
||||||
|
|
||||||
// First we'll determine the fee required for this HTLC based on if this is
|
// 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 {
|
type htlcView struct {
|
||||||
ourUpdates []*PaymentDescriptor
|
ourUpdates []*PaymentDescriptor
|
||||||
theirUpdates []*PaymentDescriptor
|
theirUpdates []*PaymentDescriptor
|
||||||
feePerKw SatPerKWeight
|
feePerKw chainfee.SatPerKWeight
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchHTLCView returns all the candidate HTLC updates which should be
|
// 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
|
// If the update wasn't already locked in, update the current fee rate
|
||||||
// to reflect this update.
|
// to reflect this update.
|
||||||
view.feePerKw = SatPerKWeight(feeUpdate.Amount.ToSatoshis())
|
view.feePerKw = chainfee.SatPerKWeight(feeUpdate.Amount.ToSatoshis())
|
||||||
|
|
||||||
if mutateState {
|
if mutateState {
|
||||||
*addHeight = nextHeight
|
*addHeight = nextHeight
|
||||||
@ -3131,9 +3134,9 @@ func (lc *LightningChannel) validateCommitmentSanity(theirLogCounter,
|
|||||||
|
|
||||||
// Ensure that the fee being applied is enough to be relayed across the
|
// Ensure that the fee being applied is enough to be relayed across the
|
||||||
// network in a reasonable time frame.
|
// 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",
|
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
|
// 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
|
// Next, we'll obtain HTLC resolutions for all the outgoing HTLC's we
|
||||||
// had on their commitment transaction.
|
// had on their commitment transaction.
|
||||||
htlcResolutions, err := extractHtlcResolutions(
|
htlcResolutions, err := extractHtlcResolutions(
|
||||||
SatPerKWeight(remoteCommit.FeePerKw), false, signer,
|
chainfee.SatPerKWeight(remoteCommit.FeePerKw), false, signer,
|
||||||
remoteCommit.Htlcs, keyRing, &chanState.LocalChanCfg,
|
remoteCommit.Htlcs, keyRing, &chanState.LocalChanCfg,
|
||||||
&chanState.RemoteChanCfg, *commitSpend.SpenderTxHash,
|
&chanState.RemoteChanCfg, *commitSpend.SpenderTxHash,
|
||||||
)
|
)
|
||||||
@ -5246,10 +5249,11 @@ type HtlcResolutions struct {
|
|||||||
// newOutgoingHtlcResolution generates a new HTLC resolution capable of
|
// newOutgoingHtlcResolution generates a new HTLC resolution capable of
|
||||||
// allowing the caller to sweep an outgoing HTLC present on either their, or
|
// allowing the caller to sweep an outgoing HTLC present on either their, or
|
||||||
// the remote party's commitment transaction.
|
// the remote party's commitment transaction.
|
||||||
func newOutgoingHtlcResolution(signer input.Signer, localChanCfg *channeldb.ChannelConfig,
|
func newOutgoingHtlcResolution(signer input.Signer,
|
||||||
commitHash chainhash.Hash, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
|
localChanCfg *channeldb.ChannelConfig, commitHash chainhash.Hash,
|
||||||
feePerKw SatPerKWeight, dustLimit btcutil.Amount, csvDelay uint32, localCommit bool,
|
htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
|
||||||
) (*OutgoingHtlcResolution, error) {
|
feePerKw chainfee.SatPerKWeight, csvDelay uint32,
|
||||||
|
localCommit bool) (*OutgoingHtlcResolution, error) {
|
||||||
|
|
||||||
op := wire.OutPoint{
|
op := wire.OutPoint{
|
||||||
Hash: commitHash,
|
Hash: commitHash,
|
||||||
@ -5388,7 +5392,7 @@ func newOutgoingHtlcResolution(signer input.Signer, localChanCfg *channeldb.Chan
|
|||||||
// TODO(roasbeef) consolidate code with above func
|
// TODO(roasbeef) consolidate code with above func
|
||||||
func newIncomingHtlcResolution(signer input.Signer, localChanCfg *channeldb.ChannelConfig,
|
func newIncomingHtlcResolution(signer input.Signer, localChanCfg *channeldb.ChannelConfig,
|
||||||
commitHash chainhash.Hash, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
|
commitHash chainhash.Hash, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
|
||||||
feePerKw SatPerKWeight, dustLimit btcutil.Amount, csvDelay uint32,
|
feePerKw chainfee.SatPerKWeight, csvDelay uint32,
|
||||||
localCommit bool) (*IncomingHtlcResolution, error) {
|
localCommit bool) (*IncomingHtlcResolution, error) {
|
||||||
|
|
||||||
op := wire.OutPoint{
|
op := wire.OutPoint{
|
||||||
@ -5542,7 +5546,7 @@ func (r *OutgoingHtlcResolution) HtlcPoint() wire.OutPoint {
|
|||||||
// extractHtlcResolutions creates a series of outgoing HTLC resolutions, and
|
// extractHtlcResolutions creates a series of outgoing HTLC resolutions, and
|
||||||
// the local key used when generating the HTLC scrips. This function is to be
|
// the local key used when generating the HTLC scrips. This function is to be
|
||||||
// used in two cases: force close, or a unilateral close.
|
// 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,
|
signer input.Signer, htlcs []channeldb.HTLC, keyRing *CommitmentKeyRing,
|
||||||
localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
|
localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
|
||||||
commitHash chainhash.Hash) (*HtlcResolutions, error) {
|
commitHash chainhash.Hash) (*HtlcResolutions, error) {
|
||||||
@ -5573,7 +5577,7 @@ func extractHtlcResolutions(feePerKw SatPerKWeight, ourCommit bool,
|
|||||||
// as we can satisfy the contract.
|
// as we can satisfy the contract.
|
||||||
ihr, err := newIncomingHtlcResolution(
|
ihr, err := newIncomingHtlcResolution(
|
||||||
signer, localChanCfg, commitHash, &htlc, keyRing,
|
signer, localChanCfg, commitHash, &htlc, keyRing,
|
||||||
feePerKw, dustLimit, uint32(csvDelay), ourCommit,
|
feePerKw, uint32(csvDelay), ourCommit,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -5585,7 +5589,7 @@ func extractHtlcResolutions(feePerKw SatPerKWeight, ourCommit bool,
|
|||||||
|
|
||||||
ohr, err := newOutgoingHtlcResolution(
|
ohr, err := newOutgoingHtlcResolution(
|
||||||
signer, localChanCfg, commitHash, &htlc, keyRing,
|
signer, localChanCfg, commitHash, &htlc, keyRing,
|
||||||
feePerKw, dustLimit, uint32(csvDelay), ourCommit,
|
feePerKw, uint32(csvDelay), ourCommit,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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.
|
// outgoing HTLC's that we'll need to claim as well.
|
||||||
txHash := commitTx.TxHash()
|
txHash := commitTx.TxHash()
|
||||||
htlcResolutions, err := extractHtlcResolutions(
|
htlcResolutions, err := extractHtlcResolutions(
|
||||||
SatPerKWeight(localCommit.FeePerKw), true, signer,
|
chainfee.SatPerKWeight(localCommit.FeePerKw), true, signer,
|
||||||
localCommit.Htlcs, keyRing, &chanState.LocalChanCfg,
|
localCommit.Htlcs, keyRing, &chanState.LocalChanCfg,
|
||||||
&chanState.RemoteChanCfg, txHash,
|
&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,
|
// validateFeeRate ensures that if the passed fee is applied to the channel,
|
||||||
// and a new commitment is created (which evaluates this fee), then the
|
// and a new commitment is created (which evaluates this fee), then the
|
||||||
// initiator of the channel does not dip below their reserve.
|
// 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
|
// We'll ensure that we can accommodate this new fee change, yet still
|
||||||
// be above our reserve balance. Otherwise, we'll reject the fee
|
// be above our reserve balance. Otherwise, we'll reject the fee
|
||||||
// update.
|
// 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
|
// 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 channel initiator, and must be called before sending update_fee to
|
||||||
// the remote.
|
// the remote.
|
||||||
func (lc *LightningChannel) UpdateFee(feePerKw SatPerKWeight) error {
|
func (lc *LightningChannel) UpdateFee(feePerKw chainfee.SatPerKWeight) error {
|
||||||
lc.Lock()
|
lc.Lock()
|
||||||
defer lc.Unlock()
|
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
|
// ReceiveUpdateFee handles an updated fee sent from remote. This method will
|
||||||
// return an error if called as channel initiator.
|
// 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()
|
lc.Lock()
|
||||||
defer lc.Unlock()
|
defer lc.Unlock()
|
||||||
|
|
||||||
@ -6213,7 +6217,7 @@ func CreateCooperativeCloseTx(fundingTxIn wire.TxIn,
|
|||||||
|
|
||||||
// CalcFee returns the commitment fee to use for the given
|
// CalcFee returns the commitment fee to use for the given
|
||||||
// fee rate (fee-per-kw).
|
// 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)
|
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
|
// NOTE: This should only be used for channels in which the local commitment is
|
||||||
// the initiator.
|
// the initiator.
|
||||||
func (lc *LightningChannel) MaxFeeRate(maxAllocation float64) SatPerKWeight {
|
func (lc *LightningChannel) MaxFeeRate(maxAllocation float64) chainfee.SatPerKWeight {
|
||||||
lc.RLock()
|
lc.RLock()
|
||||||
defer lc.RUnlock()
|
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.
|
// Ensure the fee rate doesn't dip below the fee floor.
|
||||||
maxFeeRate := maxFee / (float64(weight) / 1000)
|
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.
|
// 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
|
// CommitFeeRate returns the current fee rate of the commitment transaction in
|
||||||
// units of sat-per-kw.
|
// units of sat-per-kw.
|
||||||
func (lc *LightningChannel) CommitFeeRate() SatPerKWeight {
|
func (lc *LightningChannel) CommitFeeRate() chainfee.SatPerKWeight {
|
||||||
lc.RLock()
|
lc.RLock()
|
||||||
defer lc.RUnlock()
|
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
|
// IsPending returns true if the channel's funding transaction has been fully
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -456,8 +457,12 @@ func TestCooperativeChannelClosure(t *testing.T) {
|
|||||||
aliceDeliveryScript := bobsPrivKey[:]
|
aliceDeliveryScript := bobsPrivKey[:]
|
||||||
bobDeliveryScript := testHdSeed[:]
|
bobDeliveryScript := testHdSeed[:]
|
||||||
|
|
||||||
aliceFeeRate := SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)
|
aliceFeeRate := chainfee.SatPerKWeight(
|
||||||
bobFeeRate := SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw)
|
aliceChannel.channelState.LocalCommitment.FeePerKw,
|
||||||
|
)
|
||||||
|
bobFeeRate := chainfee.SatPerKWeight(
|
||||||
|
bobChannel.channelState.LocalCommitment.FeePerKw,
|
||||||
|
)
|
||||||
|
|
||||||
// We'll store with both Alice and Bob creating a new close proposal
|
// We'll store with both Alice and Bob creating a new close proposal
|
||||||
// with the same fee.
|
// with the same fee.
|
||||||
@ -596,7 +601,9 @@ func TestForceClose(t *testing.T) {
|
|||||||
// Factoring in the fee rate, Alice's amount should properly reflect
|
// Factoring in the fee rate, Alice's amount should properly reflect
|
||||||
// that we've added two additional HTLC to the commitment transaction.
|
// that we've added two additional HTLC to the commitment transaction.
|
||||||
totalCommitWeight := input.CommitWeight + (input.HtlcWeight * 2)
|
totalCommitWeight := input.CommitWeight + (input.HtlcWeight * 2)
|
||||||
feePerKw := SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)
|
feePerKw := chainfee.SatPerKWeight(
|
||||||
|
aliceChannel.channelState.LocalCommitment.FeePerKw,
|
||||||
|
)
|
||||||
commitFee := feePerKw.FeeForWeight(totalCommitWeight)
|
commitFee := feePerKw.FeeForWeight(totalCommitWeight)
|
||||||
expectedAmount := (aliceChannel.Capacity / 2) - htlcAmount.ToSatoshis() - commitFee
|
expectedAmount := (aliceChannel.Capacity / 2) - htlcAmount.ToSatoshis() - commitFee
|
||||||
if aliceCommitResolution.SelfOutputSignDesc.Output.Value != int64(expectedAmount) {
|
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
|
// The amount of the HTLC should be above Alice's dust limit and below
|
||||||
// Bob's dust limit.
|
// Bob's dust limit.
|
||||||
htlcSat := (btcutil.Amount(500) + htlcTimeoutFee(
|
htlcSat := (btcutil.Amount(500) + htlcTimeoutFee(
|
||||||
SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)))
|
chainfee.SatPerKWeight(
|
||||||
|
aliceChannel.channelState.LocalCommitment.FeePerKw,
|
||||||
|
),
|
||||||
|
))
|
||||||
htlcAmount := lnwire.NewMSatFromSatoshis(htlcSat)
|
htlcAmount := lnwire.NewMSatFromSatoshis(htlcSat)
|
||||||
|
|
||||||
htlc, preimage := createHTLC(0, htlcAmount)
|
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.
|
// 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)
|
feePerKw, err := estimator.EstimateFeePerKW(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to get fee: %v", err)
|
t.Fatalf("unable to get fee: %v", err)
|
||||||
@ -1268,7 +1278,9 @@ func TestChannelBalanceDustLimit(t *testing.T) {
|
|||||||
aliceBalance := aliceChannel.channelState.LocalCommitment.LocalBalance.ToSatoshis()
|
aliceBalance := aliceChannel.channelState.LocalCommitment.LocalBalance.ToSatoshis()
|
||||||
htlcSat := aliceBalance - defaultFee
|
htlcSat := aliceBalance - defaultFee
|
||||||
htlcSat += htlcSuccessFee(
|
htlcSat += htlcSuccessFee(
|
||||||
SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw),
|
chainfee.SatPerKWeight(
|
||||||
|
aliceChannel.channelState.LocalCommitment.FeePerKw,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
htlcAmount := lnwire.NewMSatFromSatoshis(htlcSat)
|
htlcAmount := lnwire.NewMSatFromSatoshis(htlcSat)
|
||||||
@ -1366,7 +1378,7 @@ func TestStateUpdatePersistence(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Also add a fee update to the update logs.
|
// Also add a fee update to the update logs.
|
||||||
fee := SatPerKWeight(333)
|
fee := chainfee.SatPerKWeight(333)
|
||||||
if err := aliceChannel.UpdateFee(fee); err != nil {
|
if err := aliceChannel.UpdateFee(fee); err != nil {
|
||||||
t.Fatalf("unable to send fee update")
|
t.Fatalf("unable to send fee update")
|
||||||
}
|
}
|
||||||
@ -1779,8 +1791,12 @@ func TestCooperativeCloseDustAdherence(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer cleanUp()
|
defer cleanUp()
|
||||||
|
|
||||||
aliceFeeRate := SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)
|
aliceFeeRate := chainfee.SatPerKWeight(
|
||||||
bobFeeRate := SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw)
|
aliceChannel.channelState.LocalCommitment.FeePerKw,
|
||||||
|
)
|
||||||
|
bobFeeRate := chainfee.SatPerKWeight(
|
||||||
|
bobChannel.channelState.LocalCommitment.FeePerKw,
|
||||||
|
)
|
||||||
|
|
||||||
setDustLimit := func(dustVal btcutil.Amount) {
|
setDustLimit := func(dustVal btcutil.Amount) {
|
||||||
aliceChannel.channelState.LocalChanCfg.DustLimit = dustVal
|
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
|
// We'll first try to increase the fee rate 5x, this should be able to
|
||||||
// be committed without any issue.
|
// be committed without any issue.
|
||||||
newFee := SatPerKWeight(baseFeeRate * 5)
|
newFee := chainfee.SatPerKWeight(baseFeeRate * 5)
|
||||||
|
|
||||||
if err := aliceChannel.UpdateFee(newFee); err != nil {
|
if err := aliceChannel.UpdateFee(newFee); err != nil {
|
||||||
t.Fatalf("unable to alice update fee: %v", err)
|
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
|
// 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
|
// fee. This should result in an error as Alice won't be able to pay
|
||||||
// this new fee rate.
|
// this new fee rate.
|
||||||
newFee = SatPerKWeight(baseFeeRate * 1000000)
|
newFee = chainfee.SatPerKWeight(baseFeeRate * 1000000)
|
||||||
if err := aliceChannel.UpdateFee(newFee); err == nil {
|
if err := aliceChannel.UpdateFee(newFee); err == nil {
|
||||||
t.Fatalf("alice should reject the fee rate")
|
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
|
// 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
|
// smaller than the initial base fee rate. The fee application and
|
||||||
// state transition should proceed without issue.
|
// state transition should proceed without issue.
|
||||||
newFee = SatPerKWeight(baseFeeRate / 10)
|
newFee = chainfee.SatPerKWeight(baseFeeRate / 10)
|
||||||
if err := aliceChannel.UpdateFee(newFee); err != nil {
|
if err := aliceChannel.UpdateFee(newFee); err != nil {
|
||||||
t.Fatalf("unable to alice update fee: %v", err)
|
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.
|
// Simulate Alice sending update fee message to bob.
|
||||||
fee := SatPerKWeight(333)
|
fee := chainfee.SatPerKWeight(333)
|
||||||
if err := aliceChannel.UpdateFee(fee); err != nil {
|
if err := aliceChannel.UpdateFee(fee); err != nil {
|
||||||
t.Fatalf("unable to send fee update")
|
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)
|
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")
|
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)
|
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")
|
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.
|
// Simulate Alice sending update fee message to bob.
|
||||||
fee := SatPerKWeight(333)
|
fee := chainfee.SatPerKWeight(333)
|
||||||
aliceChannel.UpdateFee(fee)
|
aliceChannel.UpdateFee(fee)
|
||||||
bobChannel.ReceiveUpdateFee(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)
|
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")
|
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)
|
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")
|
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)
|
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")
|
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)
|
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")
|
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
|
// Simulate Alice sending update fee message to bob
|
||||||
fee := SatPerKWeight(333)
|
fee := chainfee.SatPerKWeight(333)
|
||||||
aliceChannel.UpdateFee(fee)
|
aliceChannel.UpdateFee(fee)
|
||||||
bobChannel.ReceiveUpdateFee(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)
|
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")
|
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)
|
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")
|
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)
|
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")
|
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)
|
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")
|
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
|
// Since Alice is the channel initiator, she should fail when receiving
|
||||||
// fee update
|
// fee update
|
||||||
fee := SatPerKWeight(333)
|
fee := chainfee.SatPerKWeight(333)
|
||||||
err = aliceChannel.ReceiveUpdateFee(fee)
|
err = aliceChannel.ReceiveUpdateFee(fee)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected alice to fail receiving fee update")
|
t.Fatalf("expected alice to fail receiving fee update")
|
||||||
@ -2400,9 +2432,9 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) {
|
|||||||
defer cleanUp()
|
defer cleanUp()
|
||||||
|
|
||||||
// Simulate Alice sending update fee message to bob.
|
// Simulate Alice sending update fee message to bob.
|
||||||
fee1 := SatPerKWeight(333)
|
fee1 := chainfee.SatPerKWeight(333)
|
||||||
fee2 := SatPerKWeight(333)
|
fee2 := chainfee.SatPerKWeight(333)
|
||||||
fee := SatPerKWeight(333)
|
fee := chainfee.SatPerKWeight(333)
|
||||||
aliceChannel.UpdateFee(fee1)
|
aliceChannel.UpdateFee(fee1)
|
||||||
aliceChannel.UpdateFee(fee2)
|
aliceChannel.UpdateFee(fee2)
|
||||||
aliceChannel.UpdateFee(fee)
|
aliceChannel.UpdateFee(fee)
|
||||||
@ -2427,15 +2459,17 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) {
|
|||||||
t.Fatalf("bob unable to process alice's new commitment: %v", err)
|
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")
|
t.Fatalf("bob's feePerKw was unexpectedly locked in")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alice sending more fee updates now should not mess up the old fee
|
// Alice sending more fee updates now should not mess up the old fee
|
||||||
// they both committed to.
|
// they both committed to.
|
||||||
fee3 := SatPerKWeight(444)
|
fee3 := chainfee.SatPerKWeight(444)
|
||||||
fee4 := SatPerKWeight(555)
|
fee4 := chainfee.SatPerKWeight(555)
|
||||||
fee5 := SatPerKWeight(666)
|
fee5 := chainfee.SatPerKWeight(666)
|
||||||
aliceChannel.UpdateFee(fee3)
|
aliceChannel.UpdateFee(fee3)
|
||||||
aliceChannel.UpdateFee(fee4)
|
aliceChannel.UpdateFee(fee4)
|
||||||
aliceChannel.UpdateFee(fee5)
|
aliceChannel.UpdateFee(fee5)
|
||||||
@ -2450,7 +2484,9 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) {
|
|||||||
t.Fatalf("unable to generate bob revocation: %v", err)
|
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")
|
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)
|
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")
|
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)
|
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")
|
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
|
// Next, we'll try to add a fee rate to Alice which is 1,000,000x her
|
||||||
// starting fee rate.
|
// starting fee rate.
|
||||||
startingFeeRate := SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)
|
startingFeeRate := chainfee.SatPerKWeight(
|
||||||
|
aliceChannel.channelState.LocalCommitment.FeePerKw,
|
||||||
|
)
|
||||||
newFeeRate := startingFeeRate * 1000000
|
newFeeRate := startingFeeRate * 1000000
|
||||||
|
|
||||||
// Both Alice and Bob should reject this new fee rate as it is far too
|
// 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
|
// First, we'll fetch the current fee rate present within the
|
||||||
// commitment transactions.
|
// 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
|
// Next, we'll start a commitment update, with Alice sending a new
|
||||||
// update to double the fee rate of the commitment.
|
// 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.
|
// 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")
|
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")
|
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
|
// First, we'll fetch the current fee rate present within the
|
||||||
// commitment transactions.
|
// commitment transactions.
|
||||||
startingFeeRate := SatPerKWeight(
|
startingFeeRate := chainfee.SatPerKWeight(
|
||||||
aliceChannel.channelState.LocalCommitment.FeePerKw,
|
aliceChannel.channelState.LocalCommitment.FeePerKw,
|
||||||
)
|
)
|
||||||
newFeeRate := startingFeeRate
|
newFeeRate := startingFeeRate
|
||||||
@ -4247,10 +4295,14 @@ func TestFeeUpdateOldDiskFormat(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Both parties should now have the latest fee rate locked-in.
|
// 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")
|
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")
|
t.Fatalf("bob's feePerKw was not locked in")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4272,10 +4324,14 @@ func TestFeeUpdateOldDiskFormat(t *testing.T) {
|
|||||||
assertLogItems(0, numHTLCs+1)
|
assertLogItems(0, numHTLCs+1)
|
||||||
|
|
||||||
// ...and the final fee rate locked in.
|
// ...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")
|
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")
|
t.Fatalf("bob's feePerKw was not locked in")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6624,7 +6680,9 @@ func TestChannelMaxFeeRate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer cleanUp()
|
defer cleanUp()
|
||||||
|
|
||||||
assertMaxFeeRate := func(maxAlloc float64, expFeeRate SatPerKWeight) {
|
assertMaxFeeRate := func(maxAlloc float64,
|
||||||
|
expFeeRate chainfee.SatPerKWeight) {
|
||||||
|
|
||||||
maxFeeRate := aliceChannel.MaxFeeRate(maxAlloc)
|
maxFeeRate := aliceChannel.MaxFeeRate(maxAlloc)
|
||||||
if maxFeeRate != expFeeRate {
|
if maxFeeRate != expFeeRate {
|
||||||
t.Fatalf("expected max fee rate of %v with max "+
|
t.Fatalf("expected max fee rate of %v with max "+
|
||||||
@ -6636,5 +6694,5 @@ func TestChannelMaxFeeRate(t *testing.T) {
|
|||||||
assertMaxFeeRate(1.0, 690607734)
|
assertMaxFeeRate(1.0, 690607734)
|
||||||
assertMaxFeeRate(0.001, 690607)
|
assertMaxFeeRate(0.001, 690607)
|
||||||
assertMaxFeeRate(0.000001, 690)
|
assertMaxFeeRate(0.000001, 690)
|
||||||
assertMaxFeeRate(0.0000001, FeePerKwFloor)
|
assertMaxFeeRate(0.0000001, chainfee.FeePerKwFloor)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config is a struct which houses configuration parameters which modify the
|
// 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
|
// FeeEstimator is the implementation that the wallet will use for the
|
||||||
// calculation of on-chain transaction fees.
|
// calculation of on-chain transaction fees.
|
||||||
FeeEstimator FeeEstimator
|
FeeEstimator chainfee.Estimator
|
||||||
|
|
||||||
// ChainIO is an instance of the BlockChainIO interface. ChainIO is
|
// ChainIO is an instance of the BlockChainIO interface. ChainIO is
|
||||||
// used to lookup the existence of outputs within the UTXO set.
|
// used to lookup the existence of outputs within the UTXO set.
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/btcsuite/btcwallet/wallet/txauthor"
|
"github.com/btcsuite/btcwallet/wallet/txauthor"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddressType is an enum-like type which denotes the possible address types
|
// 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
|
// This method also takes the target fee expressed in sat/kw that should
|
||||||
// be used when crafting the transaction.
|
// be used when crafting the transaction.
|
||||||
SendOutputs(outputs []*wire.TxOut,
|
SendOutputs(outputs []*wire.TxOut,
|
||||||
feeRate SatPerKWeight) (*wire.MsgTx, error)
|
feeRate chainfee.SatPerKWeight) (*wire.MsgTx, error)
|
||||||
|
|
||||||
// CreateSimpleTx creates a Bitcoin transaction paying to the specified
|
// CreateSimpleTx creates a Bitcoin transaction paying to the specified
|
||||||
// outputs. The transaction is not broadcasted to the network. In the
|
// 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
|
// 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
|
// doesn't alter the database. A tx created with this set to true
|
||||||
// SHOULD NOT be broadcasted.
|
// SHOULD NOT be broadcasted.
|
||||||
CreateSimpleTx(outputs []*wire.TxOut, feeRate SatPerKWeight,
|
CreateSimpleTx(outputs []*wire.TxOut, feeRate chainfee.SatPerKWeight,
|
||||||
dryRun bool) (*txauthor.AuthoredTx, error)
|
dryRun bool) (*txauthor.AuthoredTx, error)
|
||||||
|
|
||||||
// ListUnspentWitness returns all unspent outputs which are version 0
|
// ListUnspentWitness returns all unspent outputs which are version 0
|
||||||
|
@ -40,6 +40,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
|
"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"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.
|
// parties to send on-chain funds to each other.
|
||||||
func sendCoins(t *testing.T, miner *rpctest.Harness,
|
func sendCoins(t *testing.T, miner *rpctest.Harness,
|
||||||
sender, receiver *lnwallet.LightningWallet, output *wire.TxOut,
|
sender, receiver *lnwallet.LightningWallet, output *wire.TxOut,
|
||||||
feeRate lnwallet.SatPerKWeight) *wire.MsgTx {
|
feeRate chainfee.SatPerKWeight) *wire.MsgTx { //nolint:unparam
|
||||||
|
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
@ -330,7 +331,7 @@ func createTestWallet(tempTestDir string, miningNode *rpctest.Harness,
|
|||||||
WalletController: wc,
|
WalletController: wc,
|
||||||
Signer: signer,
|
Signer: signer,
|
||||||
ChainIO: bio,
|
ChainIO: bio,
|
||||||
FeeEstimator: lnwallet.NewStaticFeeEstimator(2500, 0),
|
FeeEstimator: chainfee.NewStaticEstimator(2500, 0),
|
||||||
DefaultConstraints: channeldb.ChannelConstraints{
|
DefaultConstraints: channeldb.ChannelConstraints{
|
||||||
DustLimit: 500,
|
DustLimit: 500,
|
||||||
MaxPendingAmount: lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin) * 100,
|
MaxPendingAmount: lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin) * 100,
|
||||||
@ -723,7 +724,7 @@ func testReservationInitiatorBalanceBelowDustCancel(miner *rpctest.Harness,
|
|||||||
t.Fatalf("unable to create amt: %v", err)
|
t.Fatalf("unable to create amt: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
feePerKw := lnwallet.SatPerKWeight(
|
feePerKw := chainfee.SatPerKWeight(
|
||||||
numBTC * numBTC * btcutil.SatoshiPerBitcoin,
|
numBTC * numBTC * btcutil.SatoshiPerBitcoin,
|
||||||
)
|
)
|
||||||
req := &lnwallet.InitFundingReserveMsg{
|
req := &lnwallet.InitFundingReserveMsg{
|
||||||
@ -2151,7 +2152,7 @@ func testChangeOutputSpendConfirmation(r *rpctest.Harness,
|
|||||||
//
|
//
|
||||||
// TODO(wilmer): replace this once SendOutputs easily supports sending
|
// TODO(wilmer): replace this once SendOutputs easily supports sending
|
||||||
// all funds in one transaction.
|
// all funds in one transaction.
|
||||||
txFeeRate := lnwallet.SatPerKWeight(2500)
|
txFeeRate := chainfee.SatPerKWeight(2500)
|
||||||
txFee := btcutil.Amount(14380)
|
txFee := btcutil.Amount(14380)
|
||||||
output := &wire.TxOut{
|
output := &wire.TxOut{
|
||||||
Value: int64(aliceBalance - txFee),
|
Value: int64(aliceBalance - txFee),
|
||||||
@ -2247,7 +2248,7 @@ func testLastUnusedAddr(miner *rpctest.Harness,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to convert addr to script: %v", err)
|
t.Fatalf("unable to convert addr to script: %v", err)
|
||||||
}
|
}
|
||||||
feeRate := lnwallet.SatPerKWeight(2500)
|
feeRate := chainfee.SatPerKWeight(2500)
|
||||||
output := &wire.TxOut{
|
output := &wire.TxOut{
|
||||||
Value: 1000000,
|
Value: 1000000,
|
||||||
PkScript: addrScript,
|
PkScript: addrScript,
|
||||||
@ -2281,7 +2282,7 @@ func testCreateSimpleTx(r *rpctest.Harness, w *lnwallet.LightningWallet,
|
|||||||
// The test cases we will run through for all backends.
|
// The test cases we will run through for all backends.
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
outVals []int64
|
outVals []int64
|
||||||
feeRate lnwallet.SatPerKWeight
|
feeRate chainfee.SatPerKWeight
|
||||||
valid bool
|
valid bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/btcsuite/btcwallet/wtxmgr"
|
"github.com/btcsuite/btcwallet/wtxmgr"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/build"
|
"github.com/lightningnetwork/lnd/build"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
)
|
)
|
||||||
|
|
||||||
// walletLog is a logger that is initialized with no output filters. This
|
// walletLog is a logger that is initialized with no output filters. This
|
||||||
@ -34,6 +35,7 @@ func UseLogger(logger btclog.Logger) {
|
|||||||
btcwallet.UseLogger(logger)
|
btcwallet.UseLogger(logger)
|
||||||
wtxmgr.UseLogger(logger)
|
wtxmgr.UseLogger(logger)
|
||||||
chain.UseLogger(logger)
|
chain.UseLogger(logger)
|
||||||
|
chainfee.UseLogger(logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
// logClosure is used to provide a closure over expensive logging operations
|
// logClosure is used to provide a closure over expensive logging operations
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -128,7 +129,7 @@ type ChannelReservation struct {
|
|||||||
// creation of all channel reservations should be carried out via the
|
// creation of all channel reservations should be carried out via the
|
||||||
// lnwallet.InitChannelReservation interface.
|
// lnwallet.InitChannelReservation interface.
|
||||||
func NewChannelReservation(capacity, localFundingAmt btcutil.Amount,
|
func NewChannelReservation(capacity, localFundingAmt btcutil.Amount,
|
||||||
commitFeePerKw SatPerKWeight, wallet *LightningWallet,
|
commitFeePerKw chainfee.SatPerKWeight, wallet *LightningWallet,
|
||||||
id uint64, pushMSat lnwire.MilliSatoshi, chainHash *chainhash.Hash,
|
id uint64, pushMSat lnwire.MilliSatoshi, chainHash *chainhash.Hash,
|
||||||
flags lnwire.FundingFlag,
|
flags lnwire.FundingFlag,
|
||||||
tweaklessCommit bool) (*ChannelReservation, error) {
|
tweaklessCommit bool) (*ChannelReservation, error) {
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/shachain"
|
"github.com/lightningnetwork/lnd/shachain"
|
||||||
)
|
)
|
||||||
@ -233,7 +234,7 @@ func CreateTestChannels(tweaklessCommits bool) (
|
|||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
estimator := NewStaticFeeEstimator(6000, 0)
|
estimator := chainfee.NewStaticEstimator(6000, 0)
|
||||||
feePerKw, err := estimator.EstimateFeePerKW(1)
|
feePerKw, err := estimator.EstimateFeePerKW(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/shachain"
|
"github.com/lightningnetwork/lnd/shachain"
|
||||||
)
|
)
|
||||||
@ -800,7 +801,7 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) {
|
|||||||
height: test.commitment.CommitHeight,
|
height: test.commitment.CommitHeight,
|
||||||
ourBalance: test.commitment.LocalBalance,
|
ourBalance: test.commitment.LocalBalance,
|
||||||
theirBalance: test.commitment.RemoteBalance,
|
theirBalance: test.commitment.RemoteBalance,
|
||||||
feePerKw: SatPerKWeight(test.commitment.FeePerKw),
|
feePerKw: chainfee.SatPerKWeight(test.commitment.FeePerKw),
|
||||||
dustLimit: tc.dustLimit,
|
dustLimit: tc.dustLimit,
|
||||||
isOurs: true,
|
isOurs: true,
|
||||||
}
|
}
|
||||||
@ -843,7 +844,7 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) {
|
|||||||
// Generate second-level HTLC transactions for HTLCs in
|
// Generate second-level HTLC transactions for HTLCs in
|
||||||
// commitment tx.
|
// commitment tx.
|
||||||
htlcResolutions, err := extractHtlcResolutions(
|
htlcResolutions, err := extractHtlcResolutions(
|
||||||
SatPerKWeight(test.commitment.FeePerKw), true, signer,
|
chainfee.SatPerKWeight(test.commitment.FeePerKw), true, signer,
|
||||||
htlcs, keys, channel.localChanCfg, channel.remoteChanCfg,
|
htlcs, keys, channel.localChanCfg, channel.remoteChanCfg,
|
||||||
commitTx.TxHash(),
|
commitTx.TxHash(),
|
||||||
)
|
)
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chanvalidate"
|
"github.com/lightningnetwork/lnd/lnwallet/chanvalidate"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/shachain"
|
"github.com/lightningnetwork/lnd/shachain"
|
||||||
@ -89,11 +90,11 @@ type InitFundingReserveMsg struct {
|
|||||||
// of initial commitment transactions. In order to ensure timely
|
// of initial commitment transactions. In order to ensure timely
|
||||||
// confirmation, it is recommended that this fee should be generous,
|
// confirmation, it is recommended that this fee should be generous,
|
||||||
// paying some multiple of the accepted base fee rate of the network.
|
// 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
|
// FundingFeePerKw is the fee rate in sat/kw to use for the initial
|
||||||
// funding transaction.
|
// funding transaction.
|
||||||
FundingFeePerKw SatPerKWeight
|
FundingFeePerKw chainfee.SatPerKWeight
|
||||||
|
|
||||||
// PushMSat is the number of milli-satoshis that should be pushed over
|
// PushMSat is the number of milli-satoshis that should be pushed over
|
||||||
// the responder as part of the initial channel creation.
|
// 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
|
// 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
|
// the selected outputs, and a function closure to unlock them in case of an
|
||||||
// error is returned.
|
// error is returned.
|
||||||
func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerKWeight,
|
func (l *LightningWallet) selectCoinsAndChange(feeRate chainfee.SatPerKWeight,
|
||||||
amt btcutil.Amount, minConfs int32, subtractFees bool) (
|
amt btcutil.Amount, minConfs int32, subtractFees bool) (
|
||||||
*coinSelection, error) {
|
*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
|
// 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
|
// specified fee rate should be expressed in sat/kw for coin selection to
|
||||||
// function properly.
|
// function properly.
|
||||||
func coinSelect(feeRate SatPerKWeight, amt btcutil.Amount,
|
func coinSelect(feeRate chainfee.SatPerKWeight, amt btcutil.Amount,
|
||||||
coins []*Utxo) ([]*Utxo, btcutil.Amount, error) {
|
coins []*Utxo) ([]*Utxo, btcutil.Amount, error) {
|
||||||
|
|
||||||
amtNeeded := amt
|
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
|
// 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
|
// amt in total after fees, adhering to the specified fee rate. The selected
|
||||||
// coins, the final output and change values are returned.
|
// 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,
|
dustLimit btcutil.Amount, coins []*Utxo) ([]*Utxo, btcutil.Amount,
|
||||||
btcutil.Amount, error) {
|
btcutil.Amount, error) {
|
||||||
|
|
||||||
|
@ -5,12 +5,15 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"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
|
// 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
|
// with the given number of inputs and the optional change output. This matches
|
||||||
// the estimate done by the wallet.
|
// 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
|
var weightEstimate input.TxWeightEstimator
|
||||||
|
|
||||||
// All inputs.
|
// All inputs.
|
||||||
@ -39,7 +42,7 @@ func fundingFee(feeRate SatPerKWeight, numInput int, change bool) btcutil.Amount
|
|||||||
func TestCoinSelect(t *testing.T) {
|
func TestCoinSelect(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
const feeRate = SatPerKWeight(100)
|
const feeRate = chainfee.SatPerKWeight(100)
|
||||||
const dust = btcutil.Amount(100)
|
const dust = btcutil.Amount(100)
|
||||||
|
|
||||||
type testCase struct {
|
type testCase struct {
|
||||||
@ -185,7 +188,7 @@ func TestCoinSelect(t *testing.T) {
|
|||||||
func TestCoinSelectSubtractFees(t *testing.T) {
|
func TestCoinSelectSubtractFees(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
const feeRate = SatPerKWeight(100)
|
const feeRate = chainfee.SatPerKWeight(100)
|
||||||
const dustLimit = btcutil.Amount(1000)
|
const dustLimit = btcutil.Amount(1000)
|
||||||
const dust = btcutil.Amount(100)
|
const dust = btcutil.Amount(100)
|
||||||
|
|
||||||
|
5
mock.go
5
mock.go
@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The block height returned by the mock BlockChainIO's GetBestBlock.
|
// The block height returned by the mock BlockChainIO's GetBestBlock.
|
||||||
@ -271,13 +272,13 @@ func (*mockWalletController) IsOurAddress(a btcutil.Address) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (*mockWalletController) SendOutputs(outputs []*wire.TxOut,
|
func (*mockWalletController) SendOutputs(outputs []*wire.TxOut,
|
||||||
_ lnwallet.SatPerKWeight) (*wire.MsgTx, error) {
|
_ chainfee.SatPerKWeight) (*wire.MsgTx, error) {
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*mockWalletController) CreateSimpleTx(outputs []*wire.TxOut,
|
func (*mockWalletController) CreateSimpleTx(outputs []*wire.TxOut,
|
||||||
_ lnwallet.SatPerKWeight, _ bool) (*txauthor.AuthoredTx, error) {
|
_ chainfee.SatPerKWeight, _ bool) (*txauthor.AuthoredTx, error) {
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -156,7 +156,7 @@ func TestPeerChannelClosureAcceptFeeInitiator(t *testing.T) {
|
|||||||
dummyDeliveryScript),
|
dummyDeliveryScript),
|
||||||
}
|
}
|
||||||
|
|
||||||
estimator := lnwallet.NewStaticFeeEstimator(12500, 0)
|
estimator := chainfee.NewStaticEstimator(12500, 0)
|
||||||
feePerKw, err := estimator.EstimateFeePerKW(1)
|
feePerKw, err := estimator.EstimateFeePerKW(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to query fee estimator: %v", err)
|
t.Fatalf("unable to query fee estimator: %v", err)
|
||||||
@ -446,7 +446,7 @@ func TestPeerChannelClosureFeeNegotiationsInitiator(t *testing.T) {
|
|||||||
msg: respShutdown,
|
msg: respShutdown,
|
||||||
}
|
}
|
||||||
|
|
||||||
estimator := lnwallet.NewStaticFeeEstimator(12500, 0)
|
estimator := chainfee.NewStaticEstimator(12500, 0)
|
||||||
initiatorIdealFeeRate, err := estimator.EstimateFeePerKW(1)
|
initiatorIdealFeeRate, err := estimator.EstimateFeePerKW(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to query fee estimator: %v", err)
|
t.Fatalf("unable to query fee estimator: %v", err)
|
||||||
|
13
rpcserver.go
13
rpcserver.go
@ -44,6 +44,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/macaroons"
|
"github.com/lightningnetwork/lnd/macaroons"
|
||||||
"github.com/lightningnetwork/lnd/monitoring"
|
"github.com/lightningnetwork/lnd/monitoring"
|
||||||
@ -815,7 +816,7 @@ func addrPairsToOutputs(addrPairs map[string]int64) ([]*wire.TxOut, error) {
|
|||||||
// more addresses specified in the passed payment map. The payment map maps an
|
// more addresses specified in the passed payment map. The payment map maps an
|
||||||
// address to a specified output value to be sent to that address.
|
// address to a specified output value to be sent to that address.
|
||||||
func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64,
|
func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64,
|
||||||
feeRate lnwallet.SatPerKWeight) (*chainhash.Hash, error) {
|
feeRate chainfee.SatPerKWeight) (*chainhash.Hash, error) {
|
||||||
|
|
||||||
outputs, err := addrPairsToOutputs(paymentMap)
|
outputs, err := addrPairsToOutputs(paymentMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1000,7 +1001,7 @@ func (r *rpcServer) SendCoins(ctx context.Context,
|
|||||||
|
|
||||||
// Based on the passed fee related parameters, we'll determine an
|
// Based on the passed fee related parameters, we'll determine an
|
||||||
// appropriate fee rate for this transaction.
|
// appropriate fee rate for this transaction.
|
||||||
satPerKw := lnwallet.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
|
satPerKw := chainfee.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
|
||||||
feePerKw, err := sweep.DetermineFeePerKw(
|
feePerKw, err := sweep.DetermineFeePerKw(
|
||||||
r.server.cc.feeEstimator, sweep.FeePreference{
|
r.server.cc.feeEstimator, sweep.FeePreference{
|
||||||
ConfTarget: uint32(in.TargetConf),
|
ConfTarget: uint32(in.TargetConf),
|
||||||
@ -1122,7 +1123,7 @@ func (r *rpcServer) SendMany(ctx context.Context,
|
|||||||
|
|
||||||
// Based on the passed fee related parameters, we'll determine an
|
// Based on the passed fee related parameters, we'll determine an
|
||||||
// appropriate fee rate for this transaction.
|
// appropriate fee rate for this transaction.
|
||||||
satPerKw := lnwallet.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
|
satPerKw := chainfee.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
|
||||||
feePerKw, err := sweep.DetermineFeePerKw(
|
feePerKw, err := sweep.DetermineFeePerKw(
|
||||||
r.server.cc.feeEstimator, sweep.FeePreference{
|
r.server.cc.feeEstimator, sweep.FeePreference{
|
||||||
ConfTarget: uint32(in.TargetConf),
|
ConfTarget: uint32(in.TargetConf),
|
||||||
@ -1504,7 +1505,7 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
|
|||||||
|
|
||||||
// Based on the passed fee related parameters, we'll determine an
|
// Based on the passed fee related parameters, we'll determine an
|
||||||
// appropriate fee rate for the funding transaction.
|
// appropriate fee rate for the funding transaction.
|
||||||
satPerKw := lnwallet.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
|
satPerKw := chainfee.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
|
||||||
feeRate, err := sweep.DetermineFeePerKw(
|
feeRate, err := sweep.DetermineFeePerKw(
|
||||||
r.server.cc.feeEstimator, sweep.FeePreference{
|
r.server.cc.feeEstimator, sweep.FeePreference{
|
||||||
ConfTarget: uint32(in.TargetConf),
|
ConfTarget: uint32(in.TargetConf),
|
||||||
@ -1649,7 +1650,7 @@ func (r *rpcServer) OpenChannelSync(ctx context.Context,
|
|||||||
|
|
||||||
// Based on the passed fee related parameters, we'll determine an
|
// Based on the passed fee related parameters, we'll determine an
|
||||||
// appropriate fee rate for the funding transaction.
|
// appropriate fee rate for the funding transaction.
|
||||||
satPerKw := lnwallet.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
|
satPerKw := chainfee.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
|
||||||
feeRate, err := sweep.DetermineFeePerKw(
|
feeRate, err := sweep.DetermineFeePerKw(
|
||||||
r.server.cc.feeEstimator, sweep.FeePreference{
|
r.server.cc.feeEstimator, sweep.FeePreference{
|
||||||
ConfTarget: uint32(in.TargetConf),
|
ConfTarget: uint32(in.TargetConf),
|
||||||
@ -1847,7 +1848,7 @@ func (r *rpcServer) CloseChannel(in *lnrpc.CloseChannelRequest,
|
|||||||
// Based on the passed fee related parameters, we'll determine
|
// Based on the passed fee related parameters, we'll determine
|
||||||
// an appropriate fee rate for the cooperative closure
|
// an appropriate fee rate for the cooperative closure
|
||||||
// transaction.
|
// transaction.
|
||||||
satPerKw := lnwallet.SatPerKVByte(
|
satPerKw := chainfee.SatPerKVByte(
|
||||||
in.SatPerByte * 1000,
|
in.SatPerByte * 1000,
|
||||||
).FeePerKWeight()
|
).FeePerKWeight()
|
||||||
feeRate, err := sweep.DetermineFeePerKw(
|
feeRate, err := sweep.DetermineFeePerKw(
|
||||||
|
@ -44,6 +44,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/nat"
|
"github.com/lightningnetwork/lnd/nat"
|
||||||
"github.com/lightningnetwork/lnd/netann"
|
"github.com/lightningnetwork/lnd/netann"
|
||||||
@ -1136,7 +1137,7 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
if cfg.WtClient.SweepFeeRate != 0 {
|
if cfg.WtClient.SweepFeeRate != 0 {
|
||||||
// We expose the sweep fee rate in sat/byte, but the
|
// We expose the sweep fee rate in sat/byte, but the
|
||||||
// tower protocol operations on sat/kw.
|
// tower protocol operations on sat/kw.
|
||||||
sweepRateSatPerByte := lnwallet.SatPerKVByte(
|
sweepRateSatPerByte := chainfee.SatPerKVByte(
|
||||||
1000 * cfg.WtClient.SweepFeeRate,
|
1000 * cfg.WtClient.SweepFeeRate,
|
||||||
)
|
)
|
||||||
policy.SweepFeeRate = sweepRateSatPerByte.FeePerKWeight()
|
policy.SweepFeeRate = sweepRateSatPerByte.FeePerKWeight()
|
||||||
@ -3071,7 +3072,7 @@ type openChanReq struct {
|
|||||||
|
|
||||||
pushAmt lnwire.MilliSatoshi
|
pushAmt lnwire.MilliSatoshi
|
||||||
|
|
||||||
fundingFeePerKw lnwallet.SatPerKWeight
|
fundingFeePerKw chainfee.SatPerKWeight
|
||||||
|
|
||||||
private bool
|
private bool
|
||||||
|
|
||||||
|
@ -3,38 +3,38 @@ package sweep
|
|||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
)
|
)
|
||||||
|
|
||||||
// mockFeeEstimator implements a mock fee estimator. It closely resembles
|
// mockFeeEstimator implements a mock fee estimator. It closely resembles
|
||||||
// lnwallet.StaticFeeEstimator with the addition that fees can be changed for
|
// lnwallet.StaticFeeEstimator with the addition that fees can be changed for
|
||||||
// testing purposes in a thread safe manner.
|
// testing purposes in a thread safe manner.
|
||||||
type mockFeeEstimator struct {
|
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
|
// A closure that when set is used instead of the
|
||||||
// mockFeeEstimator.EstimateFeePerKW method.
|
// mockFeeEstimator.EstimateFeePerKW method.
|
||||||
estimateFeePerKW func(numBlocks uint32) (lnwallet.SatPerKWeight, error)
|
estimateFeePerKW func(numBlocks uint32) (chainfee.SatPerKWeight, error)
|
||||||
|
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMockFeeEstimator(feePerKW,
|
func newMockFeeEstimator(feePerKW,
|
||||||
relayFee lnwallet.SatPerKWeight) *mockFeeEstimator {
|
relayFee chainfee.SatPerKWeight) *mockFeeEstimator {
|
||||||
|
|
||||||
return &mockFeeEstimator{
|
return &mockFeeEstimator{
|
||||||
feePerKW: feePerKW,
|
feePerKW: feePerKW,
|
||||||
relayFee: relayFee,
|
relayFee: relayFee,
|
||||||
blocksToFee: make(map[uint32]lnwallet.SatPerKWeight),
|
blocksToFee: make(map[uint32]chainfee.SatPerKWeight),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *mockFeeEstimator) updateFees(feePerKW,
|
func (e *mockFeeEstimator) updateFees(feePerKW,
|
||||||
relayFee lnwallet.SatPerKWeight) {
|
relayFee chainfee.SatPerKWeight) {
|
||||||
|
|
||||||
e.lock.Lock()
|
e.lock.Lock()
|
||||||
defer e.lock.Unlock()
|
defer e.lock.Unlock()
|
||||||
@ -44,7 +44,7 @@ func (e *mockFeeEstimator) updateFees(feePerKW,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *mockFeeEstimator) EstimateFeePerKW(numBlocks uint32) (
|
func (e *mockFeeEstimator) EstimateFeePerKW(numBlocks uint32) (
|
||||||
lnwallet.SatPerKWeight, error) {
|
chainfee.SatPerKWeight, error) {
|
||||||
|
|
||||||
e.lock.Lock()
|
e.lock.Lock()
|
||||||
defer e.lock.Unlock()
|
defer e.lock.Unlock()
|
||||||
@ -60,7 +60,7 @@ func (e *mockFeeEstimator) EstimateFeePerKW(numBlocks uint32) (
|
|||||||
return e.feePerKW, nil
|
return e.feePerKW, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *mockFeeEstimator) RelayFeePerKW() lnwallet.SatPerKWeight {
|
func (e *mockFeeEstimator) RelayFeePerKW() chainfee.SatPerKWeight {
|
||||||
e.lock.Lock()
|
e.lock.Lock()
|
||||||
defer e.lock.Unlock()
|
defer e.lock.Unlock()
|
||||||
|
|
||||||
@ -75,4 +75,4 @@ func (e *mockFeeEstimator) Stop() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ lnwallet.FeeEstimator = (*mockFeeEstimator)(nil)
|
var _ chainfee.Estimator = (*mockFeeEstimator)(nil)
|
||||||
|
@ -16,13 +16,14 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// DefaultMaxFeeRate is the default maximum fee rate allowed within the
|
// DefaultMaxFeeRate is the default maximum fee rate allowed within the
|
||||||
// UtxoSweeper. The current value is equivalent to a fee rate of 10,000
|
// UtxoSweeper. The current value is equivalent to a fee rate of 10,000
|
||||||
// sat/vbyte.
|
// sat/vbyte.
|
||||||
DefaultMaxFeeRate = lnwallet.FeePerKwFloor * 1e4
|
DefaultMaxFeeRate = chainfee.FeePerKwFloor * 1e4
|
||||||
|
|
||||||
// DefaultFeeRateBucketSize is the default size of fee rate buckets
|
// DefaultFeeRateBucketSize is the default size of fee rate buckets
|
||||||
// we'll use when clustering inputs into buckets with similar fee rates
|
// 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
|
// lastFeeRate is the most recent fee rate used for this input within a
|
||||||
// transaction broadcast to the network.
|
// transaction broadcast to the network.
|
||||||
lastFeeRate lnwallet.SatPerKWeight
|
lastFeeRate chainfee.SatPerKWeight
|
||||||
}
|
}
|
||||||
|
|
||||||
// pendingInputs is a type alias for a set of pending inputs.
|
// 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
|
// inputCluster is a helper struct to gather a set of pending inputs that should
|
||||||
// be swept with the specified fee rate.
|
// be swept with the specified fee rate.
|
||||||
type inputCluster struct {
|
type inputCluster struct {
|
||||||
sweepFeeRate lnwallet.SatPerKWeight
|
sweepFeeRate chainfee.SatPerKWeight
|
||||||
inputs pendingInputs
|
inputs pendingInputs
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +127,7 @@ type PendingInput struct {
|
|||||||
|
|
||||||
// LastFeeRate is the most recent fee rate used for the input being
|
// LastFeeRate is the most recent fee rate used for the input being
|
||||||
// swept within a transaction broadcast to the network.
|
// 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
|
// BroadcastAttempts is the number of attempts we've made to sweept the
|
||||||
// input.
|
// input.
|
||||||
@ -182,7 +183,7 @@ type UtxoSweeper struct {
|
|||||||
|
|
||||||
currentOutputScript []byte
|
currentOutputScript []byte
|
||||||
|
|
||||||
relayFeeRate lnwallet.SatPerKWeight
|
relayFeeRate chainfee.SatPerKWeight
|
||||||
|
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
@ -197,7 +198,7 @@ type UtxoSweeperConfig struct {
|
|||||||
// FeeEstimator is used when crafting sweep transactions to estimate
|
// FeeEstimator is used when crafting sweep transactions to estimate
|
||||||
// the necessary fee relative to the expected size of the sweep
|
// the necessary fee relative to the expected size of the sweep
|
||||||
// transaction.
|
// transaction.
|
||||||
FeeEstimator lnwallet.FeeEstimator
|
FeeEstimator chainfee.Estimator
|
||||||
|
|
||||||
// PublishTransaction facilitates the process of broadcasting a signed
|
// PublishTransaction facilitates the process of broadcasting a signed
|
||||||
// transaction to the appropriate network.
|
// transaction to the appropriate network.
|
||||||
@ -235,7 +236,7 @@ type UtxoSweeperConfig struct {
|
|||||||
|
|
||||||
// MaxFeeRate is the the maximum fee rate allowed within the
|
// MaxFeeRate is the the maximum fee rate allowed within the
|
||||||
// UtxoSweeper.
|
// UtxoSweeper.
|
||||||
MaxFeeRate lnwallet.SatPerKWeight
|
MaxFeeRate chainfee.SatPerKWeight
|
||||||
|
|
||||||
// FeeRateBucketSize is the default size of fee rate buckets we'll use
|
// FeeRateBucketSize is the default size of fee rate buckets we'll use
|
||||||
// when clustering inputs into buckets with similar fee rates within the
|
// 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
|
// feeRateForPreference returns a fee rate for the given fee preference. It
|
||||||
// ensures that the fee rate respects the bounds of the UtxoSweeper.
|
// ensures that the fee rate respects the bounds of the UtxoSweeper.
|
||||||
func (s *UtxoSweeper) feeRateForPreference(
|
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
|
// Ensure a type of fee preference is specified to prevent using a
|
||||||
// default below.
|
// 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
|
// bucketForFeeReate determines the proper bucket for a fee rate. This is done
|
||||||
// in order to batch inputs with similar fee rates together.
|
// in order to batch inputs with similar fee rates together.
|
||||||
func (s *UtxoSweeper) bucketForFeeRate(
|
func (s *UtxoSweeper) bucketForFeeRate(
|
||||||
feeRate lnwallet.SatPerKWeight) lnwallet.SatPerKWeight {
|
feeRate chainfee.SatPerKWeight) chainfee.SatPerKWeight {
|
||||||
|
|
||||||
minBucket := s.relayFeeRate + lnwallet.SatPerKWeight(s.cfg.FeeRateBucketSize)
|
minBucket := s.relayFeeRate + chainfee.SatPerKWeight(s.cfg.FeeRateBucketSize)
|
||||||
return lnwallet.SatPerKWeight(
|
return chainfee.SatPerKWeight(
|
||||||
math.Ceil(float64(feeRate) / float64(minBucket)),
|
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
|
// sweep fee rate, which is determined by calculating the average fee rate of
|
||||||
// all inputs within that cluster.
|
// all inputs within that cluster.
|
||||||
func (s *UtxoSweeper) clusterBySweepFeeRate() []inputCluster {
|
func (s *UtxoSweeper) clusterBySweepFeeRate() []inputCluster {
|
||||||
bucketInputs := make(map[lnwallet.SatPerKWeight]pendingInputs)
|
bucketInputs := make(map[chainfee.SatPerKWeight]pendingInputs)
|
||||||
inputFeeRates := make(map[wire.OutPoint]lnwallet.SatPerKWeight)
|
inputFeeRates := make(map[wire.OutPoint]chainfee.SatPerKWeight)
|
||||||
|
|
||||||
// First, we'll group together all inputs with similar fee rates. This
|
// First, we'll group together all inputs with similar fee rates. This
|
||||||
// is done by determining the fee rate bucket they should belong in.
|
// 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.
|
// calculating the average fee rate of the inputs within each set.
|
||||||
inputClusters := make([]inputCluster, 0, len(bucketInputs))
|
inputClusters := make([]inputCluster, 0, len(bucketInputs))
|
||||||
for _, inputs := range bucketInputs {
|
for _, inputs := range bucketInputs {
|
||||||
var sweepFeeRate lnwallet.SatPerKWeight
|
var sweepFeeRate chainfee.SatPerKWeight
|
||||||
for op := range inputs {
|
for op := range inputs {
|
||||||
sweepFeeRate += inputFeeRates[op]
|
sweepFeeRate += inputFeeRates[op]
|
||||||
}
|
}
|
||||||
sweepFeeRate /= lnwallet.SatPerKWeight(len(inputs))
|
sweepFeeRate /= chainfee.SatPerKWeight(len(inputs))
|
||||||
inputClusters = append(inputClusters, inputCluster{
|
inputClusters = append(inputClusters, inputCluster{
|
||||||
sweepFeeRate: sweepFeeRate,
|
sweepFeeRate: sweepFeeRate,
|
||||||
inputs: inputs,
|
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
|
// 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.
|
// 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 {
|
currentHeight int32) error {
|
||||||
|
|
||||||
// Generate an output script if there isn't an unused script available.
|
// Generate an output script if there isn't an unused script available.
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -99,7 +100,7 @@ func createSweeperTestContext(t *testing.T) *sweeperTestContext {
|
|||||||
|
|
||||||
backend := newMockBackend(notifier)
|
backend := newMockBackend(notifier)
|
||||||
|
|
||||||
estimator := newMockFeeEstimator(10000, lnwallet.FeePerKwFloor)
|
estimator := newMockFeeEstimator(10000, chainfee.FeePerKwFloor)
|
||||||
|
|
||||||
publishChan := make(chan wire.MsgTx, 2)
|
publishChan := make(chan wire.MsgTx, 2)
|
||||||
ctx := &sweeperTestContext{
|
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
|
// NOTE: This assumes that transactions only have one output, as this is the
|
||||||
// only type of transaction the UtxoSweeper can create at the moment.
|
// only type of transaction the UtxoSweeper can create at the moment.
|
||||||
func assertTxFeeRate(t *testing.T, tx *wire.MsgTx,
|
func assertTxFeeRate(t *testing.T, tx *wire.MsgTx,
|
||||||
expectedFeeRate lnwallet.SatPerKWeight, inputs ...input.Input) {
|
expectedFeeRate chainfee.SatPerKWeight, inputs ...input.Input) {
|
||||||
|
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
@ -994,11 +995,11 @@ func TestDifferentFeePreferences(t *testing.T) {
|
|||||||
// this to ensure the sweeper can broadcast distinct transactions for
|
// this to ensure the sweeper can broadcast distinct transactions for
|
||||||
// each sweep with a different fee preference.
|
// each sweep with a different fee preference.
|
||||||
lowFeePref := FeePreference{ConfTarget: 12}
|
lowFeePref := FeePreference{ConfTarget: 12}
|
||||||
lowFeeRate := lnwallet.SatPerKWeight(5000)
|
lowFeeRate := chainfee.SatPerKWeight(5000)
|
||||||
ctx.estimator.blocksToFee[lowFeePref.ConfTarget] = lowFeeRate
|
ctx.estimator.blocksToFee[lowFeePref.ConfTarget] = lowFeeRate
|
||||||
|
|
||||||
highFeePref := FeePreference{ConfTarget: 6}
|
highFeePref := FeePreference{ConfTarget: 6}
|
||||||
highFeeRate := lnwallet.SatPerKWeight(10000)
|
highFeeRate := chainfee.SatPerKWeight(10000)
|
||||||
ctx.estimator.blocksToFee[highFeePref.ConfTarget] = highFeeRate
|
ctx.estimator.blocksToFee[highFeePref.ConfTarget] = highFeeRate
|
||||||
|
|
||||||
input1 := spendableInputs[0]
|
input1 := spendableInputs[0]
|
||||||
@ -1116,7 +1117,7 @@ func TestBumpFeeRBF(t *testing.T) {
|
|||||||
ctx := createSweeperTestContext(t)
|
ctx := createSweeperTestContext(t)
|
||||||
|
|
||||||
lowFeePref := FeePreference{ConfTarget: 144}
|
lowFeePref := FeePreference{ConfTarget: 144}
|
||||||
lowFeeRate := lnwallet.FeePerKwFloor
|
lowFeeRate := chainfee.FeePerKwFloor
|
||||||
ctx.estimator.blocksToFee[lowFeePref.ConfTarget] = lowFeeRate
|
ctx.estimator.blocksToFee[lowFeePref.ConfTarget] = lowFeeRate
|
||||||
|
|
||||||
// We'll first try to bump the fee of an output currently unknown to the
|
// We'll first try to bump the fee of an output currently unknown to the
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/btcsuite/btcwallet/wallet/txrules"
|
"github.com/btcsuite/btcwallet/wallet/txrules"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -31,7 +31,7 @@ type inputSet []input.Input
|
|||||||
// inputs are skipped. No input sets with a total value after fees below the
|
// inputs are skipped. No input sets with a total value after fees below the
|
||||||
// dust limit are returned.
|
// dust limit are returned.
|
||||||
func generateInputPartitionings(sweepableInputs []input.Input,
|
func generateInputPartitionings(sweepableInputs []input.Input,
|
||||||
relayFeePerKW, feePerKW lnwallet.SatPerKWeight,
|
relayFeePerKW, feePerKW chainfee.SatPerKWeight,
|
||||||
maxInputsPerTx int) ([]inputSet, error) {
|
maxInputsPerTx int) ([]inputSet, error) {
|
||||||
|
|
||||||
// Calculate dust limit based on the P2WPKH output script of the sweep
|
// 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
|
// minimizing any negative externalities we cause for the Bitcoin system as a
|
||||||
// whole.
|
// whole.
|
||||||
func getPositiveYieldInputs(sweepableInputs []input.Input, maxInputs int,
|
func getPositiveYieldInputs(sweepableInputs []input.Input, maxInputs int,
|
||||||
feePerKW lnwallet.SatPerKWeight) (int, btcutil.Amount) {
|
feePerKW chainfee.SatPerKWeight) (int, btcutil.Amount) {
|
||||||
|
|
||||||
var weightEstimate input.TxWeightEstimator
|
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.
|
// createSweepTx builds a signed tx spending the inputs to a the output script.
|
||||||
func createSweepTx(inputs []input.Input, outputPkScript []byte,
|
func createSweepTx(inputs []input.Input, outputPkScript []byte,
|
||||||
currentBlockHeight uint32, feePerKw lnwallet.SatPerKWeight,
|
currentBlockHeight uint32, feePerKw chainfee.SatPerKWeight,
|
||||||
signer input.Signer) (*wire.MsgTx, error) {
|
signer input.Signer) (*wire.MsgTx, error) {
|
||||||
|
|
||||||
inputs, txWeight := getWeightEstimate(inputs)
|
inputs, txWeight := getWeightEstimate(inputs)
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -27,7 +28,7 @@ type FeePreference struct {
|
|||||||
|
|
||||||
// FeeRate if non-zero, signals a fee pre fence expressed in the fee
|
// FeeRate if non-zero, signals a fee pre fence expressed in the fee
|
||||||
// rate expressed in sat/kw for a particular transaction.
|
// 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.
|
// 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
|
// 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
|
// value is chosen based on the two free parameters as one, or both of them can
|
||||||
// be zero.
|
// be zero.
|
||||||
func DetermineFeePerKw(feeEstimator lnwallet.FeeEstimator,
|
func DetermineFeePerKw(feeEstimator chainfee.Estimator,
|
||||||
feePref FeePreference) (lnwallet.SatPerKWeight, error) {
|
feePref FeePreference) (chainfee.SatPerKWeight, error) {
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
// If both values are set, then we'll return an error as we require a
|
// 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.
|
// internally.
|
||||||
case feePref.FeeRate != 0:
|
case feePref.FeeRate != 0:
|
||||||
feePerKW := feePref.FeeRate
|
feePerKW := feePref.FeeRate
|
||||||
if feePerKW < lnwallet.FeePerKwFloor {
|
if feePerKW < chainfee.FeePerKwFloor {
|
||||||
log.Infof("Manual fee rate input of %d sat/kw is "+
|
log.Infof("Manual fee rate input of %d sat/kw is "+
|
||||||
"too low, using %d sat/kw instead", feePerKW,
|
"too low, using %d sat/kw instead", feePerKW,
|
||||||
lnwallet.FeePerKwFloor)
|
chainfee.FeePerKwFloor)
|
||||||
|
|
||||||
feePerKW = lnwallet.FeePerKwFloor
|
feePerKW = chainfee.FeePerKwFloor
|
||||||
}
|
}
|
||||||
|
|
||||||
return feePerKW, nil
|
return feePerKW, nil
|
||||||
@ -152,10 +153,10 @@ type WalletSweepPackage struct {
|
|||||||
// by the delivery address. The sweep transaction will be crafted with the
|
// by the delivery address. The sweep transaction will be crafted with the
|
||||||
// target fee rate, and will use the utxoSource and outpointLocker as sources
|
// target fee rate, and will use the utxoSource and outpointLocker as sources
|
||||||
// for wallet funds.
|
// for wallet funds.
|
||||||
func CraftSweepAllTx(feeRate lnwallet.SatPerKWeight, blockHeight uint32,
|
func CraftSweepAllTx(feeRate chainfee.SatPerKWeight, blockHeight uint32,
|
||||||
deliveryAddr btcutil.Address, coinSelectLocker CoinSelectionLocker,
|
deliveryAddr btcutil.Address, coinSelectLocker CoinSelectionLocker,
|
||||||
utxoSource UtxoSource, outpointLocker OutpointLocker,
|
utxoSource UtxoSource, outpointLocker OutpointLocker,
|
||||||
feeEstimator lnwallet.FeeEstimator,
|
feeEstimator chainfee.Estimator,
|
||||||
signer input.Signer) (*WalletSweepPackage, error) {
|
signer input.Signer) (*WalletSweepPackage, error) {
|
||||||
|
|
||||||
// TODO(roasbeef): turn off ATPL as well when available?
|
// TODO(roasbeef): turn off ATPL as well when available?
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestDetermineFeePerKw tests that given a fee preference, the
|
// TestDetermineFeePerKw tests that given a fee preference, the
|
||||||
@ -17,8 +18,8 @@ import (
|
|||||||
func TestDetermineFeePerKw(t *testing.T) {
|
func TestDetermineFeePerKw(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
defaultFee := lnwallet.SatPerKWeight(999)
|
defaultFee := chainfee.SatPerKWeight(999)
|
||||||
relayFee := lnwallet.SatPerKWeight(300)
|
relayFee := chainfee.SatPerKWeight(300)
|
||||||
|
|
||||||
feeEstimator := newMockFeeEstimator(defaultFee, relayFee)
|
feeEstimator := newMockFeeEstimator(defaultFee, relayFee)
|
||||||
|
|
||||||
@ -35,7 +36,7 @@ func TestDetermineFeePerKw(t *testing.T) {
|
|||||||
|
|
||||||
// fee is the value the DetermineFeePerKw should return given
|
// fee is the value the DetermineFeePerKw should return given
|
||||||
// the FeePreference above
|
// the FeePreference above
|
||||||
fee lnwallet.SatPerKWeight
|
fee chainfee.SatPerKWeight
|
||||||
|
|
||||||
// fail determines if this test case should fail or not.
|
// fail determines if this test case should fail or not.
|
||||||
fail bool
|
fail bool
|
||||||
@ -43,9 +44,9 @@ func TestDetermineFeePerKw(t *testing.T) {
|
|||||||
// A fee rate below the fee rate floor should output the floor.
|
// A fee rate below the fee rate floor should output the floor.
|
||||||
{
|
{
|
||||||
feePref: FeePreference{
|
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
|
// A fee rate above the floor, should pass through and return
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/netann"
|
"github.com/lightningnetwork/lnd/netann"
|
||||||
"github.com/lightningnetwork/lnd/shachain"
|
"github.com/lightningnetwork/lnd/shachain"
|
||||||
@ -214,7 +215,7 @@ func createTestPeer(notifier chainntnfs.ChainNotifier,
|
|||||||
return nil, nil, nil, nil, err
|
return nil, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
estimator := lnwallet.NewStaticFeeEstimator(12500, 0)
|
estimator := chainfee.NewStaticEstimator(12500, 0)
|
||||||
feePerKw, err := estimator.EstimateFeePerKW(1)
|
feePerKw, err := estimator.EstimateFeePerKW(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, nil, err
|
return nil, nil, nil, nil, err
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/tlv"
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/blob"
|
"github.com/lightningnetwork/lnd/watchtower/blob"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/wtwire"
|
"github.com/lightningnetwork/lnd/watchtower/wtwire"
|
||||||
@ -19,7 +19,7 @@ type CreateSessionTLV struct {
|
|||||||
MaxUpdates uint16
|
MaxUpdates uint16
|
||||||
RewardBase uint32
|
RewardBase uint32
|
||||||
RewardRate uint32
|
RewardRate uint32
|
||||||
SweepFeeRate lnwallet.SatPerKWeight
|
SweepFeeRate chainfee.SatPerKWeight
|
||||||
|
|
||||||
tlvStream *tlv.Stream
|
tlvStream *tlv.Stream
|
||||||
}
|
}
|
||||||
@ -48,24 +48,24 @@ func DBlobType(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
|
|||||||
|
|
||||||
// ESatPerKW is an encoder for lnwallet.SatPerKWeight.
|
// ESatPerKW is an encoder for lnwallet.SatPerKWeight.
|
||||||
func ESatPerKW(w io.Writer, val interface{}, buf *[8]byte) error {
|
func ESatPerKW(w io.Writer, val interface{}, buf *[8]byte) error {
|
||||||
if v, ok := val.(*lnwallet.SatPerKWeight); ok {
|
if v, ok := val.(*chainfee.SatPerKWeight); ok {
|
||||||
return tlv.EUint64(w, uint64(*v), buf)
|
return tlv.EUint64(w, uint64(*v), buf)
|
||||||
}
|
}
|
||||||
return tlv.NewTypeForEncodingErr(val, "lnwallet.SatPerKWeight")
|
return tlv.NewTypeForEncodingErr(val, "chainfee.SatPerKWeight")
|
||||||
}
|
}
|
||||||
|
|
||||||
// DSatPerKW is an decoder for lnwallet.SatPerKWeight.
|
// DSatPerKW is an decoder for lnwallet.SatPerKWeight.
|
||||||
func DSatPerKW(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
|
func DSatPerKW(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
|
||||||
if v, ok := val.(*lnwallet.SatPerKWeight); ok {
|
if v, ok := val.(*chainfee.SatPerKWeight); ok {
|
||||||
var sat uint64
|
var sat uint64
|
||||||
err := tlv.DUint64(r, &sat, buf, l)
|
err := tlv.DUint64(r, &sat, buf, l)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
*v = lnwallet.SatPerKWeight(sat)
|
*v = chainfee.SatPerKWeight(sat)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return tlv.NewTypeForDecodingErr(val, "lnwallet.SatPerKWeight", l, 8)
|
return tlv.NewTypeForDecodingErr(val, "chainfee.SatPerKWeight", l, 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCreateSessionTLV initializes a new CreateSessionTLV message.
|
// NewCreateSessionTLV initializes a new CreateSessionTLV message.
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/blob"
|
"github.com/lightningnetwork/lnd/watchtower/blob"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
||||||
@ -86,7 +87,7 @@ func genTaskTest(
|
|||||||
toLocalAmt int64,
|
toLocalAmt int64,
|
||||||
toRemoteAmt int64,
|
toRemoteAmt int64,
|
||||||
blobType blob.Type,
|
blobType blob.Type,
|
||||||
sweepFeeRate lnwallet.SatPerKWeight,
|
sweepFeeRate chainfee.SatPerKWeight,
|
||||||
rewardScript []byte,
|
rewardScript []byte,
|
||||||
expSweepAmt int64,
|
expSweepAmt int64,
|
||||||
expRewardAmt int64,
|
expRewardAmt int64,
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/blob"
|
"github.com/lightningnetwork/lnd/watchtower/blob"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/wtpolicy"
|
"github.com/lightningnetwork/lnd/watchtower/wtpolicy"
|
||||||
)
|
)
|
||||||
@ -58,7 +58,7 @@ func ReadElement(r io.Reader, element interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
e.BlobType = blob.Type(blobType)
|
e.BlobType = blob.Type(blobType)
|
||||||
e.SweepFeeRate = lnwallet.SatPerKWeight(sweepFeeRate)
|
e.SweepFeeRate = chainfee.SatPerKWeight(sweepFeeRate)
|
||||||
|
|
||||||
// Type is still unknown to wtdb extensions, fail.
|
// Type is still unknown to wtdb extensions, fail.
|
||||||
default:
|
default:
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/blob"
|
"github.com/lightningnetwork/lnd/watchtower/blob"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,11 +28,11 @@ const (
|
|||||||
|
|
||||||
// DefaultSweepFeeRate specifies the fee rate used to construct justice
|
// DefaultSweepFeeRate specifies the fee rate used to construct justice
|
||||||
// transactions. The value is expressed in satoshis per kilo-weight.
|
// transactions. The value is expressed in satoshis per kilo-weight.
|
||||||
DefaultSweepFeeRate = lnwallet.SatPerKWeight(2500)
|
DefaultSweepFeeRate = chainfee.SatPerKWeight(2500)
|
||||||
|
|
||||||
// MinSweepFeeRate is the minimum sweep fee rate a client may use in its
|
// MinSweepFeeRate is the minimum sweep fee rate a client may use in its
|
||||||
// policy, the current value is 4 sat/vbyte.
|
// policy, the current value is 4 sat/vbyte.
|
||||||
MinSweepFeeRate = lnwallet.SatPerKWeight(1000)
|
MinSweepFeeRate = chainfee.SatPerKWeight(1000)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -97,7 +98,7 @@ type TxPolicy struct {
|
|||||||
// constructing the justice transaction. All sweep transactions created
|
// constructing the justice transaction. All sweep transactions created
|
||||||
// for this session must use this value during construction, and the
|
// for this session must use this value during construction, and the
|
||||||
// signatures must implicitly commit to the resulting output values.
|
// signatures must implicitly commit to the resulting output values.
|
||||||
SweepFeeRate lnwallet.SatPerKWeight
|
SweepFeeRate chainfee.SatPerKWeight
|
||||||
}
|
}
|
||||||
|
|
||||||
// Policy defines the negotiated parameters for a session between a client and
|
// Policy defines the negotiated parameters for a session between a client and
|
||||||
|
@ -3,7 +3,7 @@ package wtwire
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/blob"
|
"github.com/lightningnetwork/lnd/watchtower/blob"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ type CreateSession struct {
|
|||||||
// constructing the justice transaction. All sweep transactions created
|
// constructing the justice transaction. All sweep transactions created
|
||||||
// for this session must use this value during construction, and the
|
// for this session must use this value during construction, and the
|
||||||
// signatures must implicitly commit to the resulting output values.
|
// signatures must implicitly commit to the resulting output values.
|
||||||
SweepFeeRate lnwallet.SatPerKWeight
|
SweepFeeRate chainfee.SatPerKWeight
|
||||||
}
|
}
|
||||||
|
|
||||||
// A compile time check to ensure CreateSession implements the wtwire.Message
|
// A compile time check to ensure CreateSession implements the wtwire.Message
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/blob"
|
"github.com/lightningnetwork/lnd/watchtower/blob"
|
||||||
)
|
)
|
||||||
@ -74,7 +74,7 @@ func WriteElement(w io.Writer, element interface{}) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
case lnwallet.SatPerKWeight:
|
case chainfee.SatPerKWeight:
|
||||||
var b [8]byte
|
var b [8]byte
|
||||||
binary.BigEndian.PutUint64(b[:], uint64(e))
|
binary.BigEndian.PutUint64(b[:], uint64(e))
|
||||||
if _, err := w.Write(b[:]); err != nil {
|
if _, err := w.Write(b[:]); err != nil {
|
||||||
@ -194,12 +194,12 @@ func ReadElement(r io.Reader, element interface{}) error {
|
|||||||
}
|
}
|
||||||
*e = bytes
|
*e = bytes
|
||||||
|
|
||||||
case *lnwallet.SatPerKWeight:
|
case *chainfee.SatPerKWeight:
|
||||||
var b [8]byte
|
var b [8]byte
|
||||||
if _, err := io.ReadFull(r, b[:]); err != nil {
|
if _, err := io.ReadFull(r, b[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
*e = lnwallet.SatPerKWeight(binary.BigEndian.Uint64(b[:]))
|
*e = chainfee.SatPerKWeight(binary.BigEndian.Uint64(b[:]))
|
||||||
|
|
||||||
case *ErrorCode:
|
case *ErrorCode:
|
||||||
var b [2]byte
|
var b [2]byte
|
||||||
|
Loading…
Reference in New Issue
Block a user