sweep: create add constraints

This refactor prepares for the addition of specific constraints for
force sweep inputs.
This commit is contained in:
Joost Jager 2019-12-13 15:04:32 +01:00
parent 16832cefa3
commit 14237f5fd4
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7
2 changed files with 48 additions and 22 deletions

View File

@ -13,6 +13,19 @@ import (
"github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chainfee"
) )
// addConstraints defines the constraints to apply when adding an input.
type addConstraints uint8
const (
// constraintsRegular is for regular input sweeps that should have a positive
// yield.
constraintsRegular addConstraints = iota
// constraintsWallet is for wallet inputs that are only added to bring up the tx
// output value.
constraintsWallet
)
// txInputSet is an object that accumulates tx inputs and keeps running counters // txInputSet is an object that accumulates tx inputs and keeps running counters
// on various properties of the tx. // on various properties of the tx.
type txInputSet struct { type txInputSet struct {
@ -78,10 +91,12 @@ func (t *txInputSet) dustLimitReached() bool {
// add adds a new input to the set. It returns a bool indicating whether the // add adds a new input to the set. It returns a bool indicating whether the
// input was added to the set. An input is rejected if it decreases the tx // input was added to the set. An input is rejected if it decreases the tx
// output value after paying fees. // output value after paying fees.
func (t *txInputSet) add(input input.Input, fromWallet bool) bool { func (t *txInputSet) add(input input.Input, constraints addConstraints) bool {
// Stop if max inputs is reached. Do not count additional wallet inputs, // Stop if max inputs is reached. Do not count additional wallet inputs,
// because we don't know in advance how many we may need. // because we don't know in advance how many we may need.
if !fromWallet && len(t.inputs) >= t.maxInputs { if constraints != constraintsWallet &&
len(t.inputs) >= t.maxInputs {
return false return false
} }
@ -108,19 +123,33 @@ func (t *txInputSet) add(input input.Input, fromWallet bool) bool {
// added to the set. // added to the set.
newOutputValue := newInputTotal - fee newOutputValue := newInputTotal - fee
// If adding this input makes the total output value of the set // Initialize new wallet total with the current wallet total. This is
// decrease, this is a negative yield input. We don't add the input to // updated below if this input is a wallet input.
// the set and return the outcome. newWalletTotal := t.walletInputTotal
if newOutputValue <= t.outputValue {
return false // Calculate the yield of this input from the change in tx output value.
} inputYield := newOutputValue - t.outputValue
switch constraints {
// Don't sweep inputs that cost us more to sweep than they give us.
case constraintsRegular:
if inputYield <= 0 {
return false
}
// We are attaching a wallet input to raise the tx output value above
// the dust limit.
case constraintsWallet:
// Skip this wallet input if adding it would lower the output
// value.
if inputYield <= 0 {
return false
}
// If this input comes from the wallet, verify that we still gain
// something with this transaction.
if fromWallet {
// Calculate the total value that we spend in this tx from the // Calculate the total value that we spend in this tx from the
// wallet if we'd add this wallet input. // wallet if we'd add this wallet input.
newWalletTotal := t.walletInputTotal + value newWalletTotal += value
// In any case, we don't want to lose money by sweeping. If we // In any case, we don't want to lose money by sweeping. If we
// don't get more out of the tx then we put in ourselves, do not // don't get more out of the tx then we put in ourselves, do not
@ -142,10 +171,6 @@ func (t *txInputSet) add(input input.Input, fromWallet bool) bool {
return false return false
} }
// We've decided to add the wallet input. Increment the total
// wallet funds that go into this tx.
t.walletInputTotal = newWalletTotal
} }
// Update running values. // Update running values.
@ -153,6 +178,7 @@ func (t *txInputSet) add(input input.Input, fromWallet bool) bool {
t.outputValue = newOutputValue t.outputValue = newOutputValue
t.inputs = append(t.inputs, input) t.inputs = append(t.inputs, input)
t.weightEstimate = newWeightEstimate t.weightEstimate = newWeightEstimate
t.walletInputTotal = newWalletTotal
return true return true
} }
@ -171,7 +197,7 @@ func (t *txInputSet) addPositiveYieldInputs(sweepableInputs []txInput) {
// succeed because it wouldn't increase the output value, // succeed because it wouldn't increase the output value,
// return. Assuming inputs are sorted by yield, any further // return. Assuming inputs are sorted by yield, any further
// inputs wouldn't increase the output value either. // inputs wouldn't increase the output value either.
if !t.add(input, false) { if !t.add(input, constraintsRegular) {
return return
} }
} }
@ -202,7 +228,7 @@ func (t *txInputSet) tryAddWalletInputsIfNeeded() error {
// If the wallet input isn't positively-yielding at this fee // If the wallet input isn't positively-yielding at this fee
// rate, skip it. // rate, skip it.
if !t.add(input, true) { if !t.add(input, constraintsWallet) {
continue continue
} }

View File

@ -24,13 +24,13 @@ func TestTxInputSet(t *testing.T) {
// Create a 300 sat input. The fee to sweep this input to a P2WKH output // Create a 300 sat input. The fee to sweep this input to a P2WKH output
// is 439 sats. That means that this input yields -139 sats and we // is 439 sats. That means that this input yields -139 sats and we
// expect it not to be added. // expect it not to be added.
if set.add(createP2WKHInput(300), false) { if set.add(createP2WKHInput(300), constraintsRegular) {
t.Fatal("expected add of negatively yielding input to fail") t.Fatal("expected add of negatively yielding input to fail")
} }
// A 700 sat input should be accepted into the set, because it yields // A 700 sat input should be accepted into the set, because it yields
// positively. // positively.
if !set.add(createP2WKHInput(700), false) { if !set.add(createP2WKHInput(700), constraintsRegular) {
t.Fatal("expected add of positively yielding input to succeed") t.Fatal("expected add of positively yielding input to succeed")
} }
@ -45,7 +45,7 @@ func TestTxInputSet(t *testing.T) {
// Add a 1000 sat input. This increases the tx fee to 712 sats. The tx // Add a 1000 sat input. This increases the tx fee to 712 sats. The tx
// output should now be 1000+700 - 712 = 988 sats. // output should now be 1000+700 - 712 = 988 sats.
if !set.add(createP2WKHInput(1000), false) { if !set.add(createP2WKHInput(1000), constraintsRegular) {
t.Fatal("expected add of positively yielding input to succeed") t.Fatal("expected add of positively yielding input to succeed")
} }
if set.outputValue != 988 { if set.outputValue != 988 {
@ -70,7 +70,7 @@ func TestTxInputSetFromWallet(t *testing.T) {
// Add a 700 sat input to the set. It yields positively, but doesn't // Add a 700 sat input to the set. It yields positively, but doesn't
// reach the output dust limit. // reach the output dust limit.
if !set.add(createP2WKHInput(700), false) { if !set.add(createP2WKHInput(700), constraintsRegular) {
t.Fatal("expected add of positively yielding input to succeed") t.Fatal("expected add of positively yielding input to succeed")
} }
if set.dustLimitReached() { if set.dustLimitReached() {