lnwallet: allow callers to specify fee for funding transaction in funding flow

In this commit, we modify the funding reservation workflow slightly to
allow callers to specify their own custom fee when initialization a
funding workflow. This gives power-users the ability to control exactly
how much in fees are paid for each new funding transaction.
This commit is contained in:
Olaoluwa Osuntokun 2017-11-23 00:30:57 -06:00
parent 36256f3f39
commit 6d10677ef5
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21
2 changed files with 39 additions and 33 deletions

View File

@ -134,7 +134,7 @@ type ChannelReservation struct {
// used only internally by lnwallet. In order to concurrent safety, the // used only internally by lnwallet. In order to concurrent safety, the
// 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, fundingAmt, feePerKw btcutil.Amount, func NewChannelReservation(capacity, fundingAmt, commitFeePerKw btcutil.Amount,
wallet *LightningWallet, id uint64, pushMSat lnwire.MilliSatoshi, wallet *LightningWallet, id uint64, pushMSat lnwire.MilliSatoshi,
chainHash *chainhash.Hash) *ChannelReservation { chainHash *chainhash.Hash) *ChannelReservation {
@ -144,7 +144,9 @@ func NewChannelReservation(capacity, fundingAmt, feePerKw btcutil.Amount,
initiator bool initiator bool
) )
commitFee := btcutil.Amount((int64(feePerKw) * CommitWeight) / 1000) commitFee := btcutil.Amount(
(int64(commitFeePerKw) * CommitWeight) / 1000,
)
fundingMSat := lnwire.NewMSatFromSatoshis(fundingAmt) fundingMSat := lnwire.NewMSatFromSatoshis(fundingAmt)
capacityMSat := lnwire.NewMSatFromSatoshis(capacity) capacityMSat := lnwire.NewMSatFromSatoshis(capacity)
@ -213,13 +215,13 @@ func NewChannelReservation(capacity, fundingAmt, feePerKw btcutil.Amount,
LocalCommitment: channeldb.ChannelCommitment{ LocalCommitment: channeldb.ChannelCommitment{
LocalBalance: ourBalance, LocalBalance: ourBalance,
RemoteBalance: theirBalance, RemoteBalance: theirBalance,
FeePerKw: feePerKw, FeePerKw: commitFeePerKw,
CommitFee: commitFee, CommitFee: commitFee,
}, },
RemoteCommitment: channeldb.ChannelCommitment{ RemoteCommitment: channeldb.ChannelCommitment{
LocalBalance: ourBalance, LocalBalance: ourBalance,
RemoteBalance: theirBalance, RemoteBalance: theirBalance,
FeePerKw: feePerKw, FeePerKw: commitFeePerKw,
CommitFee: commitFee, CommitFee: commitFee,
}, },
Db: wallet.Cfg.Database, Db: wallet.Cfg.Database,

View File

@ -94,11 +94,15 @@ type initFundingReserveMsg struct {
// amount of funds the remote party contributes (if any). // amount of funds the remote party contributes (if any).
capacity btcutil.Amount capacity btcutil.Amount
// feePerKw is the accepted satoshis/Kw fee for the funding // commitFeePerKw is the starting accepted satoshis/Kw fee for the set
// transaction. In order to ensure timely confirmation, it is // of initial commitment transactions. In order to ensure timely
// recommended that this fee should be generous, paying some multiple // confirmation, it is recommended that this fee should be generous,
// of the accepted base fee rate of the network. // paying some multiple of the accepted base fee rate of the network.
feePerKw btcutil.Amount commitFeePerKw btcutil.Amount
// fundingFeePerWeight is the fee rate in satoshis per eight unit to
// use for the initial funding transaction.
fundingFeePerWeight btcutil.Amount
// 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.
@ -443,7 +447,7 @@ out:
// commitment transaction is valid. // commitment transaction is valid.
func (l *LightningWallet) InitChannelReservation( func (l *LightningWallet) InitChannelReservation(
capacity, ourFundAmt btcutil.Amount, pushMSat lnwire.MilliSatoshi, capacity, ourFundAmt btcutil.Amount, pushMSat lnwire.MilliSatoshi,
feePerKw btcutil.Amount, commitFeePerKw, fundingFeePerWeight btcutil.Amount,
theirID *btcec.PublicKey, theirAddr *net.TCPAddr, theirID *btcec.PublicKey, theirAddr *net.TCPAddr,
chainHash *chainhash.Hash) (*ChannelReservation, error) { chainHash *chainhash.Hash) (*ChannelReservation, error) {
@ -451,15 +455,16 @@ func (l *LightningWallet) InitChannelReservation(
respChan := make(chan *ChannelReservation, 1) respChan := make(chan *ChannelReservation, 1)
l.msgChan <- &initFundingReserveMsg{ l.msgChan <- &initFundingReserveMsg{
chainHash: chainHash, chainHash: chainHash,
nodeID: theirID, nodeID: theirID,
nodeAddr: theirAddr, nodeAddr: theirAddr,
fundingAmount: ourFundAmt, fundingAmount: ourFundAmt,
capacity: capacity, capacity: capacity,
feePerKw: feePerKw, commitFeePerKw: commitFeePerKw,
pushMSat: pushMSat, fundingFeePerWeight: fundingFeePerWeight,
err: errChan, pushMSat: pushMSat,
resp: respChan, err: errChan,
resp: respChan,
} }
return <-respChan, <-errChan return <-respChan, <-errChan
@ -488,7 +493,7 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg
id := atomic.AddUint64(&l.nextFundingID, 1) id := atomic.AddUint64(&l.nextFundingID, 1)
reservation := NewChannelReservation(req.capacity, req.fundingAmount, reservation := NewChannelReservation(req.capacity, req.fundingAmount,
req.feePerKw, l, id, req.pushMSat, l.Cfg.NetParams.GenesisHash) req.commitFeePerKw, l, id, req.pushMSat, l.Cfg.NetParams.GenesisHash)
// Grab the mutex on the ChannelReservation to ensure thread-safety // Grab the mutex on the ChannelReservation to ensure thread-safety
reservation.Lock() reservation.Lock()
@ -501,14 +506,12 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg
// don't need to perform any coin selection. Otherwise, attempt to // don't need to perform any coin selection. Otherwise, attempt to
// obtain enough coins to meet the required funding amount. // obtain enough coins to meet the required funding amount.
if req.fundingAmount != 0 { if req.fundingAmount != 0 {
// Coin selection is done on the basis of sat-per-weight, so // Coin selection is done on the basis of sat-per-weight, we'll
// we'll query the fee estimator for a fee to use to ensure the // use the passed sat/byte passed in to perform coin selection.
// funding transaction gets into the _next_ block. err := l.selectCoinsAndChange(
// req.fundingFeePerWeight, req.fundingAmount,
// TODO(roasbeef): shouldn't be targeting next block reservation.ourContribution,
satPerWeight := l.Cfg.FeeEstimator.EstimateFeePerWeight(1) )
err := l.selectCoinsAndChange(satPerWeight, req.fundingAmount,
reservation.ourContribution)
if err != nil { if err != nil {
req.err <- err req.err <- err
req.resp <- nil req.resp <- nil
@ -1255,7 +1258,7 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) {
// within the passed contribution's inputs. If necessary, a change address will // within the passed contribution's inputs. If necessary, a change address will
// also be generated. // also be generated.
// TODO(roasbeef): remove hardcoded fees and req'd confs for outputs. // TODO(roasbeef): remove hardcoded fees and req'd confs for outputs.
func (l *LightningWallet) selectCoinsAndChange(feeRatePerWeight uint64, func (l *LightningWallet) selectCoinsAndChange(feeRatePerWeight btcutil.Amount,
amt btcutil.Amount, contribution *ChannelContribution) error { amt btcutil.Amount, contribution *ChannelContribution) error {
// We hold the coin select mutex while querying for outputs, and // We hold the coin select mutex while querying for outputs, and
@ -1264,8 +1267,8 @@ func (l *LightningWallet) selectCoinsAndChange(feeRatePerWeight uint64,
l.coinSelectMtx.Lock() l.coinSelectMtx.Lock()
defer l.coinSelectMtx.Unlock() defer l.coinSelectMtx.Unlock()
walletLog.Infof("Performing coin selection using %v sat/weight as fee "+ walletLog.Infof("Performing funding tx coin selection using %v "+
"rate", feeRatePerWeight) "sat/weight as fee rate", int64(feeRatePerWeight))
// Find all unlocked unspent witness outputs with greater than 1 // Find all unlocked unspent witness outputs with greater than 1
// confirmation. // confirmation.
@ -1387,7 +1390,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/byte for coin selection to // specified fee rate should be expressed in sat/byte for coin selection to
// function properly. // function properly.
func coinSelect(feeRatePerWeight uint64, amt btcutil.Amount, func coinSelect(feeRatePerWeight, amt btcutil.Amount,
coins []*Utxo) ([]*Utxo, btcutil.Amount, error) { coins []*Utxo) ([]*Utxo, btcutil.Amount, error) {
amtNeeded := amt amtNeeded := amt
@ -1432,7 +1435,8 @@ func coinSelect(feeRatePerWeight uint64, amt btcutil.Amount,
// coin amount by the estimate required fee, performing another // coin amount by the estimate required fee, performing another
// round of coin selection. // round of coin selection.
requiredFee := btcutil.Amount( requiredFee := btcutil.Amount(
uint64(weightEstimate.Weight()) * feeRatePerWeight) uint64(weightEstimate.Weight()) * uint64(feeRatePerWeight),
)
if overShootAmt < requiredFee { if overShootAmt < requiredFee {
amtNeeded = amt + requiredFee amtNeeded = amt + requiredFee
continue continue