input+sweep: log input witness types instead of CSV/CLTV count

This commit is contained in:
Oliver Gugger 2019-10-23 13:00:25 +02:00
parent 8ed7583448
commit 05096b0c2d
No known key found for this signature in database
GPG Key ID: 8E4256593F177720
4 changed files with 62 additions and 52 deletions

@ -35,9 +35,8 @@ type WitnessType interface {
SizeUpperBound() (int, bool, error) SizeUpperBound() (int, bool, error)
// AddWeightEstimation adds the estimated size of the witness in bytes // AddWeightEstimation adds the estimated size of the witness in bytes
// to the given weight estimator and returns the number of // to the given weight estimator.
// CSVs/CLTVs used by the script. AddWeightEstimation(e *TxWeightEstimator) error
AddWeightEstimation(estimator *TxWeightEstimator) (int, int, error)
} }
// StandardWitnessType is a numeric representation of standard pre-defined types // StandardWitnessType is a numeric representation of standard pre-defined types
@ -160,6 +159,12 @@ func (wt StandardWitnessType) String() string {
case HtlcSecondLevelRevoke: case HtlcSecondLevelRevoke:
return "HtlcSecondLevelRevoke" return "HtlcSecondLevelRevoke"
case WitnessKeyHash:
return "WitnessKeyHash"
case NestedWitnessKeyHash:
return "NestedWitnessKeyHash"
default: default:
return fmt.Sprintf("Unknown WitnessType: %v", uint32(wt)) return fmt.Sprintf("Unknown WitnessType: %v", uint32(wt))
} }
@ -368,42 +373,25 @@ func (wt StandardWitnessType) SizeUpperBound() (int, bool, error) {
} }
// AddWeightEstimation adds the estimated size of the witness in bytes to the // AddWeightEstimation adds the estimated size of the witness in bytes to the
// given weight estimator and returns the number of CSVs/CLTVs used by the // given weight estimator.
// script.
// //
// NOTE: This is part of the WitnessType interface. // NOTE: This is part of the WitnessType interface.
func (wt StandardWitnessType) AddWeightEstimation( func (wt StandardWitnessType) AddWeightEstimation(e *TxWeightEstimator) error {
estimator *TxWeightEstimator) (int, int, error) {
var (
csvCount = 0
cltvCount = 0
)
// For fee estimation purposes, we'll now attempt to obtain an // For fee estimation purposes, we'll now attempt to obtain an
// upper bound on the weight this input will add when fully // upper bound on the weight this input will add when fully
// populated. // populated.
size, isNestedP2SH, err := wt.SizeUpperBound() size, isNestedP2SH, err := wt.SizeUpperBound()
if err != nil { if err != nil {
return 0, 0, err return err
} }
// If this is a nested P2SH input, then we'll need to factor in // If this is a nested P2SH input, then we'll need to factor in
// the additional data push within the sigScript. // the additional data push within the sigScript.
if isNestedP2SH { if isNestedP2SH {
estimator.AddNestedP2WSHInput(size) e.AddNestedP2WSHInput(size)
} else { } else {
estimator.AddWitnessInput(size) e.AddWitnessInput(size)
} }
switch wt { return nil
case CommitmentTimeLock,
HtlcOfferedTimeoutSecondLevel,
HtlcAcceptedSuccessSecondLevel:
csvCount++
case HtlcOfferedRemoteTimeout:
cltvCount++
}
return csvCount, cltvCount, nil
} }

@ -339,7 +339,7 @@ func assertTxFeeRate(t *testing.T, tx *wire.MsgTx,
outputAmt := tx.TxOut[0].Value outputAmt := tx.TxOut[0].Value
fee := btcutil.Amount(inputAmt - outputAmt) fee := btcutil.Amount(inputAmt - outputAmt)
_, txWeight, _, _ := getWeightEstimate(inputs) _, txWeight := getWeightEstimate(inputs)
expectedFee := expectedFeeRate.FeeForWeight(txWeight) expectedFee := expectedFeeRate.FeeForWeight(txWeight)
if fee != expectedFee { if fee != expectedFee {

@ -3,6 +3,7 @@ package sweep
import ( import (
"fmt" "fmt"
"sort" "sort"
"strings"
"github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/txscript"
@ -171,10 +172,10 @@ func createSweepTx(inputs []input.Input, outputPkScript []byte,
currentBlockHeight uint32, feePerKw lnwallet.SatPerKWeight, currentBlockHeight uint32, feePerKw lnwallet.SatPerKWeight,
signer input.Signer) (*wire.MsgTx, error) { signer input.Signer) (*wire.MsgTx, error) {
inputs, txWeight, csvCount, cltvCount := getWeightEstimate(inputs) inputs, txWeight := getWeightEstimate(inputs)
log.Infof("Creating sweep transaction for %v inputs (%v CSV, %v CLTV) "+ log.Infof("Creating sweep transaction for %v inputs (%s) "+
"using %v sat/kw", len(inputs), csvCount, cltvCount, "using %v sat/kw", len(inputs), inputTypeSummary(inputs),
int64(feePerKw)) int64(feePerKw))
txFee := feePerKw.FeeForWeight(txWeight) txFee := feePerKw.FeeForWeight(txWeight)
@ -253,7 +254,7 @@ func createSweepTx(inputs []input.Input, outputPkScript []byte,
// getWeightEstimate returns a weight estimate for the given inputs. // getWeightEstimate returns a weight estimate for the given inputs.
// Additionally, it returns counts for the number of csv and cltv inputs. // Additionally, it returns counts for the number of csv and cltv inputs.
func getWeightEstimate(inputs []input.Input) ([]input.Input, int64, int, int) { func getWeightEstimate(inputs []input.Input) ([]input.Input, int64) {
// We initialize a weight estimator so we can accurately asses the // We initialize a weight estimator so we can accurately asses the
// amount of fees we need to pay for this sweep transaction. // amount of fees we need to pay for this sweep transaction.
// //
@ -268,15 +269,12 @@ func getWeightEstimate(inputs []input.Input) ([]input.Input, int64, int, int) {
// For each output, use its witness type to determine the estimate // For each output, use its witness type to determine the estimate
// weight of its witness, and add it to the proper set of spendable // weight of its witness, and add it to the proper set of spendable
// outputs. // outputs.
var ( var sweepInputs []input.Input
sweepInputs []input.Input
csvCount, cltvCount int
)
for i := range inputs { for i := range inputs {
inp := inputs[i] inp := inputs[i]
wt := inp.WitnessType() wt := inp.WitnessType()
inpCsv, inpCltv, err := wt.AddWeightEstimation(&weightEstimate) err := wt.AddWeightEstimation(&weightEstimate)
if err != nil { if err != nil {
log.Warn(err) log.Warn(err)
@ -284,12 +282,38 @@ func getWeightEstimate(inputs []input.Input) ([]input.Input, int64, int, int) {
// given. // given.
continue continue
} }
csvCount += inpCsv
cltvCount += inpCltv
sweepInputs = append(sweepInputs, inp) sweepInputs = append(sweepInputs, inp)
} }
txWeight := int64(weightEstimate.Weight()) return sweepInputs, int64(weightEstimate.Weight())
}
return sweepInputs, txWeight, csvCount, cltvCount
// inputSummary returns a string containing a human readable summary about the
// witness types of a list of inputs.
func inputTypeSummary(inputs []input.Input) string {
// Count each input by the string representation of its witness type.
// We also keep track of the keys so we can later sort by them to get
// a stable output.
counts := make(map[string]uint32)
keys := make([]string, 0, len(inputs))
for _, i := range inputs {
key := i.WitnessType().String()
_, ok := counts[key]
if !ok {
counts[key] = 0
keys = append(keys, key)
}
counts[key]++
}
sort.Strings(keys)
// Return a nice string representation of the counts by comma joining a
// slice.
var parts []string
for _, witnessType := range keys {
part := fmt.Sprintf("%d %s", counts[witnessType], witnessType)
parts = append(parts, part)
}
return strings.Join(parts, ", ")
} }

@ -14,9 +14,10 @@ var (
input.HtlcOfferedRemoteTimeout, input.HtlcOfferedRemoteTimeout,
input.WitnessKeyHash, input.WitnessKeyHash,
} }
expectedWeight = int64(1459) expectedWeight = int64(1459)
expectedCsv = 2 expectedSummary = "1 CommitmentTimeLock, 1 " +
expectedCltv = 1 "HtlcAcceptedSuccessSecondLevel, 1 HtlcOfferedRemoteTimeout, " +
"1 WitnessKeyHash"
) )
// TestWeightEstimate tests that the estimated weight and number of CSVs/CLTVs // TestWeightEstimate tests that the estimated weight and number of CSVs/CLTVs
@ -33,17 +34,14 @@ func TestWeightEstimate(t *testing.T) {
)) ))
} }
_, weight, csv, cltv := getWeightEstimate(inputs) _, weight := getWeightEstimate(inputs)
if weight != expectedWeight { if weight != expectedWeight {
t.Fatalf("unexpected weight. expected %d but got %d.", t.Fatalf("unexpected weight. expected %d but got %d.",
expectedWeight, weight) expectedWeight, weight)
} }
if csv != expectedCsv { summary := inputTypeSummary(inputs)
t.Fatalf("unexpected csv count. expected %d but got %d.", if summary != expectedSummary {
expectedCsv, csv) t.Fatalf("unexpected summary. expected %s but got %s.",
} expectedSummary, summary)
if cltv != expectedCltv {
t.Fatalf("unexpected cltv count. expected %d but got %d.",
expectedCltv, cltv)
} }
} }