cnct: use sweeper in commit resolver

Now that the sweeper is available, it isn't necessary anymore for the
commit resolver to craft its own sweep tx. Instead it can offer its
input to the sweeper and wait for the outcome.
This commit is contained in:
Joost Jager committed 2019-02-01 09:20:45 +01:00
1 parent b7387a5972
commit e486340106
2 files changed
+48 -95

No files matched your search

-1
View File
@@ -294,7 +294,6 @@ func TestContractInsertionRetrieval(t *testing.T) {
resolved: false, resolved: false,
broadcastHeight: 109, broadcastHeight: 109,
chanPoint: testChanPoint1, chanPoint: testChanPoint1,
sweepTx: nil,
}, },
} }
+48 -94
View File
@@ -1,17 +1,14 @@
package contractcourt package contractcourt
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"github.com/lightningnetwork/lnd/input"
"io" "io"
"io/ioutil"
"github.com/lightningnetwork/lnd/input"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/sweep"
) )
// commitSweepResolver is a resolver that will attempt to sweep the commitment // commitSweepResolver is a resolver that will attempt to sweep the commitment
@@ -34,11 +31,6 @@ type commitSweepResolver struct {
// chanPoint is the channel point of the original contract. // chanPoint is the channel point of the original contract.
chanPoint wire.OutPoint chanPoint wire.OutPoint
// sweepTx is the fully signed transaction which when broadcast, will
// sweep the commitment output into an output under control by the
// source wallet.
sweepTx *wire.MsgTx
ResolverKit ResolverKit
} }
@@ -87,20 +79,14 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
return nil, fmt.Errorf("quitting") return nil, fmt.Errorf("quitting")
} }
// TODO(roasbeef): checkpoint tx confirmed?
// We're dealing with our commitment transaction if the delay on the // We're dealing with our commitment transaction if the delay on the
// resolution isn't zero. // resolution isn't zero.
isLocalCommitTx := c.commitResolution.MaturityDelay != 0 isLocalCommitTx := c.commitResolution.MaturityDelay != 0
switch { if !isLocalCommitTx {
// If the sweep transaction isn't already generated, and the remote // We'll craft an input with all the information required for
// party broadcast the commitment transaction then we'll create it now. // the sweeper to create a fully valid sweeping transaction to
case c.sweepTx == nil && !isLocalCommitTx: // recover these coins.
// As we haven't already generated the sweeping transaction,
// we'll now craft an input with all the information required
// to create a fully valid sweeping transaction to recover
// these coins.
inp := input.MakeBaseInput( inp := input.MakeBaseInput(
&c.commitResolution.SelfOutPoint, &c.commitResolution.SelfOutPoint,
input.CommitmentNoDelay, input.CommitmentNoDelay,
@@ -108,64 +94,44 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
c.broadcastHeight, c.broadcastHeight,
) )
// With out input constructed, we'll now request that the // With our input constructed, we'll now offer it to the
// sweeper construct a valid sweeping transaction for this // sweeper.
// input. log.Infof("%T(%v): sweeping commit output", c, c.chanPoint)
//
// TODO: Set tx lock time to current block height instead of resultChan, err := c.Sweeper.SweepInput(&inp)
// zero. Will be taken care of once sweeper implementation is
// complete.
//
// TODO: Use time-based sweeper and result chan.
c.sweepTx, err = c.Sweeper.CreateSweepTx(
[]input.Input{&inp},
sweep.FeePreference{
ConfTarget: sweepConfTarget,
}, 0,
)
if err != nil { if err != nil {
return nil, err log.Errorf("%T(%v): unable to sweep input: %v",
}
log.Infof("%T(%v): sweeping commit output with tx=%v", c,
c.chanPoint, spew.Sdump(c.sweepTx))
// With the sweep transaction constructed, we'll now Checkpoint
// our state.
if err := c.Checkpoint(c); err != nil {
log.Errorf("unable to Checkpoint: %v", err)
return nil, err
}
// With the sweep transaction checkpointed, we'll now publish
// the transaction. Upon restart, the resolver will immediately
// take the case below since the sweep tx is checkpointed.
err := c.PublishTx(c.sweepTx)
if err != nil && err != lnwallet.ErrDoubleSpend {
log.Errorf("%T(%v): unable to publish sweep tx: %v",
c, c.chanPoint, err) c, c.chanPoint, err)
return nil, err return nil, err
} }
// If the sweep transaction has been generated, and the remote party // Sweeper is going to join this input with other inputs if
// broadcast the commit transaction, we'll republish it for reliability // possible and publish the sweep tx. When the sweep tx
// to ensure it confirms. The resolver will enter this case after // confirms, it signals us through the result channel with the
// checkpointing in the case above, ensuring we reliably on restarts. // outcome. Wait for this to happen.
case c.sweepTx != nil && !isLocalCommitTx: select {
err := c.PublishTx(c.sweepTx) case sweepResult := <-resultChan:
if err != nil && err != lnwallet.ErrDoubleSpend { if sweepResult.Err != nil {
log.Errorf("%T(%v): unable to publish sweep tx: %v", log.Errorf("%T(%v): unable to sweep input: %v",
c, c.chanPoint, err) c, c.chanPoint, sweepResult.Err)
return nil, err return nil, err
} }
// Otherwise, this is our commitment transaction, So we'll obtain the log.Infof("ChannelPoint(%v) commit tx is fully resolved by "+
// sweep transaction once the commitment output has been spent. "sweep tx: %v", c.chanPoint, sweepResult.Tx.TxHash())
case c.sweepTx == nil && isLocalCommitTx: case <-c.Quit:
// Otherwise, if we're dealing with our local commitment return nil, fmt.Errorf("quitting")
// transaction, then the output we need to sweep has been sent }
// to the nursery for incubation. In this case, we'll wait
// until the commitment output has been spent. c.resolved = true
return nil, c.Checkpoint(c)
}
// Otherwise we are dealing with a local commitment transaction and the
// output we need to sweep has been sent to the nursery for incubation.
// In this case, we'll wait until the commitment output has been spent.
spendNtfn, err := c.Notifier.RegisterSpendNtfn( spendNtfn, err := c.Notifier.RegisterSpendNtfn(
&c.commitResolution.SelfOutPoint, &c.commitResolution.SelfOutPoint,
c.commitResolution.SelfOutputSignDesc.Output.PkScript, c.commitResolution.SelfOutputSignDesc.Output.PkScript,
@@ -178,6 +144,7 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
log.Infof("%T(%v): waiting for commit output to be swept", c, log.Infof("%T(%v): waiting for commit output to be swept", c,
c.chanPoint) c.chanPoint)
var sweepTx *wire.MsgTx
select { select {
case commitSpend, ok := <-spendNtfn.Spend: case commitSpend, ok := <-spendNtfn.Spend:
if !ok { if !ok {
@@ -187,10 +154,10 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
// Once we detect the commitment output has been spent, // Once we detect the commitment output has been spent,
// we'll extract the spending transaction itself, as we // we'll extract the spending transaction itself, as we
// now consider this to be our sweep transaction. // now consider this to be our sweep transaction.
c.sweepTx = commitSpend.SpendingTx sweepTx = commitSpend.SpendingTx
log.Infof("%T(%v): commit output swept by txid=%v", log.Infof("%T(%v): commit output swept by txid=%v",
c, c.chanPoint, c.sweepTx.TxHash()) c, c.chanPoint, sweepTx.TxHash())
if err := c.Checkpoint(c); err != nil { if err := c.Checkpoint(c); err != nil {
log.Errorf("unable to Checkpoint: %v", err) log.Errorf("unable to Checkpoint: %v", err)
@@ -199,15 +166,14 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
case <-c.Quit: case <-c.Quit:
return nil, fmt.Errorf("quitting") return nil, fmt.Errorf("quitting")
} }
}
log.Infof("%T(%v): waiting for commit sweep txid=%v conf", c, c.chanPoint, log.Infof("%T(%v): waiting for commit sweep txid=%v conf", c, c.chanPoint,
c.sweepTx.TxHash()) sweepTx.TxHash())
// Now we'll wait until the sweeping transaction has been fully // Now we'll wait until the sweeping transaction has been fully
// confirmed. Once it's confirmed, we can mark this contract resolved. // confirmed. Once it's confirmed, we can mark this contract resolved.
sweepTXID := c.sweepTx.TxHash() sweepTXID := sweepTx.TxHash()
sweepingScript := c.sweepTx.TxOut[0].PkScript sweepingScript := sweepTx.TxOut[0].PkScript
confNtfn, err = c.Notifier.RegisterConfirmationsNtfn( confNtfn, err = c.Notifier.RegisterConfirmationsNtfn(
&sweepTXID, sweepingScript, 1, c.broadcastHeight, &sweepTXID, sweepingScript, 1, c.broadcastHeight,
) )
@@ -272,9 +238,9 @@ func (c *commitSweepResolver) Encode(w io.Writer) error {
return err return err
} }
if c.sweepTx != nil { // Previously a sweep tx was serialized at this point. Refactoring
return c.sweepTx.Serialize(w) // removed this, but keep in mind that this data may still be present in
} // the database.
return nil return nil
} }
@@ -303,22 +269,10 @@ func (c *commitSweepResolver) Decode(r io.Reader) error {
return err return err
} }
txBytes, err := ioutil.ReadAll(r) // Previously a sweep tx was deserialized at this point. Refactoring
if err != nil { // removed this, but keep in mind that this data may still be present in
return err // the database.
}
if len(txBytes) == 0 {
return nil
}
txReader := bytes.NewReader(txBytes)
tx := &wire.MsgTx{}
if err := tx.Deserialize(txReader); err != nil {
return nil
}
c.sweepTx = tx
return nil return nil
} }