sweep: wrap weight estimator
Preparation for a cpfp-aware weight estimator. For cpfp, a regular weight estimator isn't sufficient, because it needs to take into account the weight of the parent transaction(s) as well.
This commit is contained in:
parent
2ebfb64b9b
commit
3e3d8487fb
@ -33,7 +33,7 @@ const (
|
|||||||
type txInputSetState struct {
|
type txInputSetState struct {
|
||||||
// weightEstimate is the (worst case) tx weight with the current set of
|
// weightEstimate is the (worst case) tx weight with the current set of
|
||||||
// inputs.
|
// inputs.
|
||||||
weightEstimate input.TxWeightEstimator
|
weightEstimate *weightEstimator
|
||||||
|
|
||||||
// inputTotal is the total value of all inputs.
|
// inputTotal is the total value of all inputs.
|
||||||
inputTotal btcutil.Amount
|
inputTotal btcutil.Amount
|
||||||
@ -54,7 +54,7 @@ type txInputSetState struct {
|
|||||||
|
|
||||||
func (t *txInputSetState) clone() txInputSetState {
|
func (t *txInputSetState) clone() txInputSetState {
|
||||||
s := txInputSetState{
|
s := txInputSetState{
|
||||||
weightEstimate: t.weightEstimate,
|
weightEstimate: t.weightEstimate.clone(),
|
||||||
inputTotal: t.inputTotal,
|
inputTotal: t.inputTotal,
|
||||||
outputValue: t.outputValue,
|
outputValue: t.outputValue,
|
||||||
walletInputTotal: t.walletInputTotal,
|
walletInputTotal: t.walletInputTotal,
|
||||||
@ -95,15 +95,20 @@ func newTxInputSet(wallet Wallet, feePerKW,
|
|||||||
btcutil.Amount(relayFee.FeePerKVByte()),
|
btcutil.Amount(relayFee.FeePerKVByte()),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
state := txInputSetState{
|
||||||
|
weightEstimate: newWeightEstimator(),
|
||||||
|
}
|
||||||
|
|
||||||
b := txInputSet{
|
b := txInputSet{
|
||||||
feePerKW: feePerKW,
|
feePerKW: feePerKW,
|
||||||
dustLimit: dustLimit,
|
dustLimit: dustLimit,
|
||||||
maxInputs: maxInputs,
|
maxInputs: maxInputs,
|
||||||
wallet: wallet,
|
wallet: wallet,
|
||||||
|
txInputSetState: state,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the sweep tx output to the weight estimate.
|
// Add the sweep tx output to the weight estimate.
|
||||||
b.weightEstimate.AddP2WKHOutput()
|
b.weightEstimate.addP2WKHOutput()
|
||||||
|
|
||||||
return &b
|
return &b
|
||||||
}
|
}
|
||||||
@ -126,29 +131,22 @@ func (t *txInputSet) addToState(inp input.Input, constraints addConstraints) *tx
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can ignore error, because it has already been checked when
|
|
||||||
// calculating the yields.
|
|
||||||
size, isNestedP2SH, _ := inp.WitnessType().SizeUpperBound()
|
|
||||||
|
|
||||||
// Clone the current set state.
|
// Clone the current set state.
|
||||||
s := t.clone()
|
s := t.clone()
|
||||||
|
|
||||||
// Add the new input.
|
// Add the new input.
|
||||||
s.inputs = append(s.inputs, inp)
|
s.inputs = append(s.inputs, inp)
|
||||||
|
|
||||||
// Add weight of the new input.
|
// Can ignore error, because it has already been checked when
|
||||||
if isNestedP2SH {
|
// calculating the yields.
|
||||||
s.weightEstimate.AddNestedP2WSHInput(size)
|
_ = s.weightEstimate.add(inp)
|
||||||
} else {
|
|
||||||
s.weightEstimate.AddWitnessInput(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the value of the new input.
|
// Add the value of the new input.
|
||||||
value := btcutil.Amount(inp.SignDesc().Output.Value)
|
value := btcutil.Amount(inp.SignDesc().Output.Value)
|
||||||
s.inputTotal += value
|
s.inputTotal += value
|
||||||
|
|
||||||
// Recalculate the tx fee.
|
// Recalculate the tx fee.
|
||||||
weight := s.weightEstimate.Weight()
|
weight := s.weightEstimate.weight()
|
||||||
fee := t.feePerKW.FeeForWeight(int64(weight))
|
fee := t.feePerKW.FeeForWeight(int64(weight))
|
||||||
|
|
||||||
// Calculate the new output value.
|
// Calculate the new output value.
|
||||||
|
@ -120,7 +120,7 @@ func generateInputPartitionings(sweepableInputs []txInput,
|
|||||||
"has yield=%v, weight=%v",
|
"has yield=%v, weight=%v",
|
||||||
inputCount, len(txInputs.inputs)-inputCount,
|
inputCount, len(txInputs.inputs)-inputCount,
|
||||||
txInputs.outputValue-txInputs.walletInputTotal,
|
txInputs.outputValue-txInputs.walletInputTotal,
|
||||||
txInputs.weightEstimate.Weight())
|
txInputs.weightEstimate.weight())
|
||||||
|
|
||||||
sets = append(sets, txInputs.inputs)
|
sets = append(sets, txInputs.inputs)
|
||||||
sweepableInputs = sweepableInputs[inputCount:]
|
sweepableInputs = sweepableInputs[inputCount:]
|
||||||
@ -222,11 +222,11 @@ func getWeightEstimate(inputs []input.Input) ([]input.Input, int64) {
|
|||||||
//
|
//
|
||||||
// TODO(roasbeef): can be more intelligent about buffering outputs to
|
// TODO(roasbeef): can be more intelligent about buffering outputs to
|
||||||
// be more efficient on-chain.
|
// be more efficient on-chain.
|
||||||
var weightEstimate input.TxWeightEstimator
|
weightEstimate := newWeightEstimator()
|
||||||
|
|
||||||
// Our sweep transaction will pay to a single segwit p2wkh address,
|
// Our sweep transaction will pay to a single segwit p2wkh address,
|
||||||
// ensure it contributes to our weight estimate.
|
// ensure it contributes to our weight estimate.
|
||||||
weightEstimate.AddP2WKHOutput()
|
weightEstimate.addP2WKHOutput()
|
||||||
|
|
||||||
// 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
|
||||||
@ -235,8 +235,7 @@ func getWeightEstimate(inputs []input.Input) ([]input.Input, int64) {
|
|||||||
for i := range inputs {
|
for i := range inputs {
|
||||||
inp := inputs[i]
|
inp := inputs[i]
|
||||||
|
|
||||||
wt := inp.WitnessType()
|
err := weightEstimate.add(inp)
|
||||||
err := wt.AddWeightEstimation(&weightEstimate)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(err)
|
log.Warn(err)
|
||||||
|
|
||||||
@ -248,7 +247,7 @@ func getWeightEstimate(inputs []input.Input) ([]input.Input, int64) {
|
|||||||
sweepInputs = append(sweepInputs, inp)
|
sweepInputs = append(sweepInputs, inp)
|
||||||
}
|
}
|
||||||
|
|
||||||
return sweepInputs, int64(weightEstimate.Weight())
|
return sweepInputs, int64(weightEstimate.weight())
|
||||||
}
|
}
|
||||||
|
|
||||||
// inputSummary returns a string containing a human readable summary about the
|
// inputSummary returns a string containing a human readable summary about the
|
||||||
|
40
sweep/weight_estimator.go
Normal file
40
sweep/weight_estimator.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package sweep
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/lightningnetwork/lnd/input"
|
||||||
|
)
|
||||||
|
|
||||||
|
// weightEstimator wraps a standard weight estimator instance.
|
||||||
|
type weightEstimator struct {
|
||||||
|
estimator input.TxWeightEstimator
|
||||||
|
}
|
||||||
|
|
||||||
|
// newWeightEstimator instantiates a new sweeper weight estimator.
|
||||||
|
func newWeightEstimator() *weightEstimator {
|
||||||
|
return &weightEstimator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clone returns a copy of this weight estimator.
|
||||||
|
func (w *weightEstimator) clone() *weightEstimator {
|
||||||
|
return &weightEstimator{
|
||||||
|
estimator: w.estimator,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add adds the weight of the given input to the weight estimate.
|
||||||
|
func (w *weightEstimator) add(inp input.Input) error {
|
||||||
|
wt := inp.WitnessType()
|
||||||
|
|
||||||
|
return wt.AddWeightEstimation(&w.estimator)
|
||||||
|
}
|
||||||
|
|
||||||
|
// addP2WKHOutput updates the weight estimate to account for an additional
|
||||||
|
// native P2WKH output.
|
||||||
|
func (w *weightEstimator) addP2WKHOutput() {
|
||||||
|
w.estimator.AddP2WKHOutput()
|
||||||
|
}
|
||||||
|
|
||||||
|
// weight gets the estimated weight of the transaction.
|
||||||
|
func (w *weightEstimator) weight() int {
|
||||||
|
return w.estimator.Weight()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user