lnwallet: Use TxWeightEstimator for funding transaction.

This commit is contained in:
Jim Posen 2017-09-25 18:45:46 -07:00 committed by Olaoluwa Osuntokun
parent fb32c3f73d
commit ced530f98e

@ -504,13 +504,13 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg
// don't need to perform any coin selection. Otherwise, attempt to
// obtain enough coins to meet the required funding amount.
if req.fundingAmount != 0 {
// Coin selection is done on the basis of sat-per-byte, so
// Coin selection is done on the basis of sat-per-weight, so
// we'll query the fee estimator for a fee to use to ensure the
// funding transaction gets into the _next_ block.
//
// TODO(roasbeef): shouldn't be targeting next block
satPerByte := l.Cfg.FeeEstimator.EstimateFeePerByte(1)
err := l.selectCoinsAndChange(satPerByte, req.fundingAmount,
satPerWeight := l.Cfg.FeeEstimator.EstimateFeePerWeight(1)
err := l.selectCoinsAndChange(satPerWeight, req.fundingAmount,
reservation.ourContribution)
if err != nil {
req.err <- err
@ -1039,20 +1039,19 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs
// Next, create the spending scriptSig, and then verify that the script
// is complete, allowing us to spend from the funding transaction.
theirCommitSig := msg.theirCommitmentSig
channelValue := int64(res.partialState.Capacity)
hashCache := txscript.NewTxSigHashes(&commitTx)
sigHash, err := txscript.CalcWitnessSigHash(witnessScript, hashCache,
txscript.SigHashAll, &commitTx, 0, channelValue)
if err != nil {
msg.err <- fmt.Errorf("counterparty's commitment signature is "+
"invalid: %v", err)
msg.err <- err
msg.completeChan <- nil
return
}
// Verify that we've received a valid signature from the remote party
// for our version of the commitment transaction.
theirCommitSig := msg.theirCommitmentSig
sig, err := btcec.ParseSignature(theirCommitSig, btcec.S256())
if err != nil {
msg.err <- err
@ -1268,8 +1267,8 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) {
// within the passed contribution's inputs. If necessary, a change address will
// also be generated.
// TODO(roasbeef): remove hardcoded fees and req'd confs for outputs.
func (l *LightningWallet) selectCoinsAndChange(feeRate uint64, amt btcutil.Amount,
contribution *ChannelContribution) error {
func (l *LightningWallet) selectCoinsAndChange(feeRatePerWeight uint64,
amt btcutil.Amount, contribution *ChannelContribution) error {
// We hold the coin select mutex while querying for outputs, and
// performing coin selection in order to avoid inadvertent double
@ -1277,8 +1276,8 @@ func (l *LightningWallet) selectCoinsAndChange(feeRate uint64, amt btcutil.Amoun
l.coinSelectMtx.Lock()
defer l.coinSelectMtx.Unlock()
walletLog.Infof("Performing coin selection using %v sat/byte as fee "+
"rate", feeRate)
walletLog.Infof("Performing coin selection using %v sat/weight as fee "+
"rate", feeRatePerWeight)
// Find all unlocked unspent witness outputs with greater than 1
// confirmation.
@ -1291,7 +1290,7 @@ func (l *LightningWallet) selectCoinsAndChange(feeRate uint64, amt btcutil.Amoun
// Perform coin selection over our available, unlocked unspent outputs
// in order to find enough coins to meet the funding amount
// requirements.
selectedCoins, changeAmt, err := coinSelect(feeRate, amt, coins)
selectedCoins, changeAmt, err := coinSelect(feeRatePerWeight, amt, coins)
if err != nil {
return err
}
@ -1419,33 +1418,9 @@ func selectInputs(amt btcutil.Amount, coins []*Utxo) (btcutil.Amount, []*wire.Ou
// 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
// function properly.
func coinSelect(feeRate uint64, amt btcutil.Amount,
func coinSelect(feeRatePerWeight uint64, amt btcutil.Amount,
coins []*Utxo) ([]*wire.OutPoint, btcutil.Amount, error) {
const (
// txOverhead is the overhead of a transaction residing within
// the version number and lock time.
txOverhead = 8
// p2wkhSpendSize an estimate of the number of bytes it takes
// to spend a p2wkh output.
//
// (p2wkh witness) + txid + index + varint script size + sequence
// TODO(roasbeef): div by 3 due to witness size?
p2wkhSpendSize = (1 + 73 + 1 + 33) + 32 + 4 + 1 + 4
// p2wkhOutputSize is an estimate of the size of a regualr
// p2wkh output.
//
// 8 (output) + 1 (var int script) + 22 (p2wkh output)
p2wkhOutputSize = 8 + 1 + 22
// p2wkhOutputSize is an estimate of the p2wsh funding uotput.
p2wshOutputSize = 8 + 1 + 34
)
var estimatedSize int
amtNeeded := amt
for {
// First perform an initial round of coin selection to estimate
@ -1455,10 +1430,20 @@ func coinSelect(feeRate uint64, amt btcutil.Amount,
return nil, 0, err
}
// Based on the selected coins, estimate the size of the final
// fully signed transaction.
estimatedSize = ((len(selectedUtxos) * p2wkhSpendSize) +
p2wshOutputSize + txOverhead)
var weightEstimate TxWeightEstimator
for range selectedUtxos {
// Assume all selected inputs are P2WKH inputs.
// TODO: Handle wallets that have non-witness UTXOs.
weightEstimate.AddP2WKHInput()
}
// Channel funding multisig output is P2WSH.
weightEstimate.AddP2WSHOutput()
// Assume that change output is a P2WKH output.
// TODO: Handle wallets that generate non-witness change addresses.
weightEstimate.AddP2WKHOutput()
// The difference between the selected amount and the amount
// requested will be used to pay fees, and generate a change
@ -1469,9 +1454,10 @@ func coinSelect(feeRate uint64, amt btcutil.Amount,
// amount isn't enough to pay fees, then increase the requested
// coin amount by the estimate required fee, performing another
// round of coin selection.
requiredFee := btcutil.Amount(uint64(estimatedSize) * feeRate)
requiredFee := btcutil.Amount(
uint64(weightEstimate.Weight()) * feeRatePerWeight)
if overShootAmt < requiredFee {
amtNeeded += requiredFee
amtNeeded = amt + requiredFee
continue
}