sweep: update getInputWitnessSizeUpperBound to be aware of nested p2sh
In this commit, we update the `getInputWitnessSizeUpperBound` and all its callers to be aware of nested p2sh witness inputs. We do so by adding another bool which is true if the output is a nested p2sh output. If so, then in order to properly estimate the total weight, the caller needs to factor in the non-witness data of the additional sigScript data push.
This commit is contained in:
parent
40f0dbb5e6
commit
4ad175c16d
@ -10,6 +10,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/davecgh/go-spew/spew"
|
||||||
"github.com/lightningnetwork/lnd/build"
|
"github.com/lightningnetwork/lnd/build"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
@ -376,7 +377,8 @@ func TestNegativeInput(t *testing.T) {
|
|||||||
if !testTxIns(&sweepTx1, []*wire.OutPoint{
|
if !testTxIns(&sweepTx1, []*wire.OutPoint{
|
||||||
largeInput.OutPoint(), positiveInput.OutPoint(),
|
largeInput.OutPoint(), positiveInput.OutPoint(),
|
||||||
}) {
|
}) {
|
||||||
t.Fatal("Tx does not contain expected inputs")
|
t.Fatalf("Tx does not contain expected inputs: %v",
|
||||||
|
spew.Sdump(sweepTx1))
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.backend.mine()
|
ctx.backend.mine()
|
||||||
|
@ -55,7 +55,7 @@ func generateInputPartitionings(sweepableInputs []Input,
|
|||||||
// on the signature length, which is not known yet at this point.
|
// on the signature length, which is not known yet at this point.
|
||||||
yields := make(map[wire.OutPoint]int64)
|
yields := make(map[wire.OutPoint]int64)
|
||||||
for _, input := range sweepableInputs {
|
for _, input := range sweepableInputs {
|
||||||
size, err := getInputWitnessSizeUpperBound(input)
|
size, _, err := getInputWitnessSizeUpperBound(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"failed adding input weight: %v", err)
|
"failed adding input weight: %v", err)
|
||||||
@ -125,10 +125,14 @@ func getPositiveYieldInputs(sweepableInputs []Input, maxInputs int,
|
|||||||
for idx, input := range sweepableInputs {
|
for idx, input := range sweepableInputs {
|
||||||
// Can ignore error, because it has already been checked when
|
// Can ignore error, because it has already been checked when
|
||||||
// calculating the yields.
|
// calculating the yields.
|
||||||
size, _ := getInputWitnessSizeUpperBound(input)
|
size, isNestedP2SH, _ := getInputWitnessSizeUpperBound(input)
|
||||||
|
|
||||||
// Keep a running weight estimate of the input set.
|
// Keep a running weight estimate of the input set.
|
||||||
|
if isNestedP2SH {
|
||||||
|
weightEstimate.AddNestedP2WSHInput(size)
|
||||||
|
} else {
|
||||||
weightEstimate.AddWitnessInput(size)
|
weightEstimate.AddWitnessInput(size)
|
||||||
|
}
|
||||||
|
|
||||||
newTotal := total + btcutil.Amount(input.SignDesc().Output.Value)
|
newTotal := total + btcutil.Amount(input.SignDesc().Output.Value)
|
||||||
|
|
||||||
@ -247,45 +251,54 @@ func createSweepTx(inputs []Input, outputPkScript []byte,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getInputWitnessSizeUpperBound returns the maximum length of the witness for
|
// getInputWitnessSizeUpperBound returns the maximum length of the witness for
|
||||||
// the given input if it would be included in a tx.
|
// the given input if it would be included in a tx. We also return if the
|
||||||
func getInputWitnessSizeUpperBound(input Input) (int, error) {
|
// output itself is a nested p2sh output, if so then we need to take into
|
||||||
|
// account the extra sigScript data size.
|
||||||
|
func getInputWitnessSizeUpperBound(input Input) (int, bool, error) {
|
||||||
switch input.WitnessType() {
|
switch input.WitnessType() {
|
||||||
|
|
||||||
// Outputs on a remote commitment transaction that pay directly
|
// Outputs on a remote commitment transaction that pay directly to us.
|
||||||
// to us.
|
case lnwallet.WitnessKeyHash:
|
||||||
|
fallthrough
|
||||||
case lnwallet.CommitmentNoDelay:
|
case lnwallet.CommitmentNoDelay:
|
||||||
return lnwallet.P2WKHWitnessSize, nil
|
return lnwallet.P2WKHWitnessSize, false, nil
|
||||||
|
|
||||||
// Outputs on a past commitment transaction that pay directly
|
// Outputs on a past commitment transaction that pay directly
|
||||||
// to us.
|
// to us.
|
||||||
case lnwallet.CommitmentTimeLock:
|
case lnwallet.CommitmentTimeLock:
|
||||||
return lnwallet.ToLocalTimeoutWitnessSize, nil
|
return lnwallet.ToLocalTimeoutWitnessSize, false, nil
|
||||||
|
|
||||||
// Outgoing second layer HTLC's that have confirmed within the
|
// Outgoing second layer HTLC's that have confirmed within the
|
||||||
// chain, and the output they produced is now mature enough to
|
// chain, and the output they produced is now mature enough to
|
||||||
// sweep.
|
// sweep.
|
||||||
case lnwallet.HtlcOfferedTimeoutSecondLevel:
|
case lnwallet.HtlcOfferedTimeoutSecondLevel:
|
||||||
return lnwallet.ToLocalTimeoutWitnessSize, nil
|
return lnwallet.ToLocalTimeoutWitnessSize, false, nil
|
||||||
|
|
||||||
// Incoming second layer HTLC's that have confirmed within the
|
// Incoming second layer HTLC's that have confirmed within the
|
||||||
// chain, and the output they produced is now mature enough to
|
// chain, and the output they produced is now mature enough to
|
||||||
// sweep.
|
// sweep.
|
||||||
case lnwallet.HtlcAcceptedSuccessSecondLevel:
|
case lnwallet.HtlcAcceptedSuccessSecondLevel:
|
||||||
return lnwallet.ToLocalTimeoutWitnessSize, nil
|
return lnwallet.ToLocalTimeoutWitnessSize, false, nil
|
||||||
|
|
||||||
// An HTLC on the commitment transaction of the remote party,
|
// An HTLC on the commitment transaction of the remote party,
|
||||||
// that has had its absolute timelock expire.
|
// that has had its absolute timelock expire.
|
||||||
case lnwallet.HtlcOfferedRemoteTimeout:
|
case lnwallet.HtlcOfferedRemoteTimeout:
|
||||||
return lnwallet.AcceptedHtlcTimeoutWitnessSize, nil
|
return lnwallet.AcceptedHtlcTimeoutWitnessSize, false, nil
|
||||||
|
|
||||||
// An HTLC on the commitment transaction of the remote party,
|
// An HTLC on the commitment transaction of the remote party,
|
||||||
// that can be swept with the preimage.
|
// that can be swept with the preimage.
|
||||||
case lnwallet.HtlcAcceptedRemoteSuccess:
|
case lnwallet.HtlcAcceptedRemoteSuccess:
|
||||||
return lnwallet.OfferedHtlcSuccessWitnessSize, nil
|
return lnwallet.OfferedHtlcSuccessWitnessSize, false, nil
|
||||||
|
|
||||||
|
// A nested P2SH input that has a p2wkh witness script. We'll mark this
|
||||||
|
// as nested P2SH so the caller can estimate the weight properly
|
||||||
|
// including the sigScript.
|
||||||
|
case lnwallet.NestedWitnessKeyHash:
|
||||||
|
return lnwallet.P2WKHWitnessSize, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, fmt.Errorf("unexpected witness type: %v", input.WitnessType())
|
return 0, false, fmt.Errorf("unexpected witness type: %v",
|
||||||
|
input.WitnessType())
|
||||||
}
|
}
|
||||||
|
|
||||||
// getWeightEstimate returns a weight estimate for the given inputs.
|
// getWeightEstimate returns a weight estimate for the given inputs.
|
||||||
@ -312,7 +325,10 @@ func getWeightEstimate(inputs []Input) ([]Input, int64, int, int) {
|
|||||||
for i := range inputs {
|
for i := range inputs {
|
||||||
input := inputs[i]
|
input := inputs[i]
|
||||||
|
|
||||||
size, err := getInputWitnessSizeUpperBound(input)
|
// For fee estimation purposes, we'll now attempt to obtain an
|
||||||
|
// upper bound on the weight this input will add when fully
|
||||||
|
// populated.
|
||||||
|
size, isNestedP2SH, err := getInputWitnessSizeUpperBound(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(err)
|
log.Warn(err)
|
||||||
|
|
||||||
@ -320,7 +336,14 @@ func getWeightEstimate(inputs []Input) ([]Input, int64, int, int) {
|
|||||||
// given.
|
// given.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a nested P2SH input, then we'll need to factor in
|
||||||
|
// the additional data push within the sigScript.
|
||||||
|
if isNestedP2SH {
|
||||||
|
weightEstimate.AddNestedP2WSHInput(size)
|
||||||
|
} else {
|
||||||
weightEstimate.AddWitnessInput(size)
|
weightEstimate.AddWitnessInput(size)
|
||||||
|
}
|
||||||
|
|
||||||
switch input.WitnessType() {
|
switch input.WitnessType() {
|
||||||
case lnwallet.CommitmentTimeLock,
|
case lnwallet.CommitmentTimeLock,
|
||||||
|
Loading…
Reference in New Issue
Block a user