contractcourt: persist commit sweep resolutions
This commit is contained in:
parent
d0ec872ef3
commit
d8a4b37c0e
@ -55,6 +55,10 @@ const (
|
||||
|
||||
// ResolverTypeOutgoingHtlc represents resolution of an outgoing htlc.
|
||||
ResolverTypeOutgoingHtlc ResolverType = 2
|
||||
|
||||
// ResolverTypeCommit represents resolution of our time locked commit
|
||||
// when we force close.
|
||||
ResolverTypeCommit ResolverType = 3
|
||||
)
|
||||
|
||||
// ResolverOutcome indicates the outcome for the resolver that that the contract
|
||||
|
@ -6,9 +6,11 @@ import (
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/sweep"
|
||||
@ -235,11 +237,13 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var sweepTxID chainhash.Hash
|
||||
|
||||
// Sweeper is going to join this input with other inputs if
|
||||
// possible and publish the sweep tx. When the sweep tx
|
||||
// confirms, it signals us through the result channel with the
|
||||
// outcome. Wait for this to happen.
|
||||
recovered := true
|
||||
outcome := channeldb.ResolverOutcomeClaimed
|
||||
select {
|
||||
case sweepResult := <-resultChan:
|
||||
switch sweepResult.Err {
|
||||
@ -250,7 +254,7 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
|
||||
// the contract.
|
||||
c.log.Warnf("local commitment output was swept by "+
|
||||
"remote party via %v", sweepResult.Tx.TxHash())
|
||||
recovered = false
|
||||
outcome = channeldb.ResolverOutcomeUnclaimed
|
||||
case nil:
|
||||
// No errors, therefore continue processing.
|
||||
c.log.Infof("local commitment output fully resolved by "+
|
||||
@ -262,22 +266,30 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
|
||||
|
||||
return nil, sweepResult.Err
|
||||
}
|
||||
|
||||
sweepTxID = sweepResult.Tx.TxHash()
|
||||
|
||||
case <-c.quit:
|
||||
return nil, errResolverShuttingDown
|
||||
}
|
||||
|
||||
// Funds have been swept and balance is no longer in limbo.
|
||||
c.reportLock.Lock()
|
||||
if recovered {
|
||||
if outcome == channeldb.ResolverOutcomeClaimed {
|
||||
// We only record the balance as recovered if it actually came
|
||||
// back to us.
|
||||
c.currentReport.RecoveredBalance = c.currentReport.LimboBalance
|
||||
}
|
||||
c.currentReport.LimboBalance = 0
|
||||
c.reportLock.Unlock()
|
||||
|
||||
report := c.currentReport.resolverReport(
|
||||
&sweepTxID, channeldb.ResolverTypeCommit, outcome,
|
||||
)
|
||||
c.resolved = true
|
||||
return nil, c.Checkpoint(c, nil)
|
||||
|
||||
// Checkpoint the resolver with a closure that will write the outcome
|
||||
// of the resolver and its sweep transaction to disk.
|
||||
return nil, c.Checkpoint(c, report)
|
||||
}
|
||||
|
||||
// Stop signals the resolver to cancel any current resolution processes, and
|
||||
|
@ -169,13 +169,44 @@ func TestCommitSweepResolverNoDelay(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := newCommitSweepResolverTestContext(t, &res)
|
||||
|
||||
// Replace our checkpoint with one which will push reports into a
|
||||
// channel for us to consume. We replace this function on the resolver
|
||||
// itself because it is created by the test context.
|
||||
reportChan := make(chan *channeldb.ResolverReport)
|
||||
ctx.resolver.Checkpoint = func(_ ContractResolver,
|
||||
reports ...*channeldb.ResolverReport) error {
|
||||
|
||||
// Send all of our reports into the channel.
|
||||
for _, report := range reports {
|
||||
reportChan <- report
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx.resolve()
|
||||
|
||||
ctx.notifier.confChan <- &chainntnfs.TxConfirmation{}
|
||||
spendTx := &wire.MsgTx{}
|
||||
spendHash := spendTx.TxHash()
|
||||
ctx.notifier.confChan <- &chainntnfs.TxConfirmation{
|
||||
Tx: spendTx,
|
||||
}
|
||||
|
||||
// No csv delay, so the input should be swept immediately.
|
||||
<-ctx.sweeper.sweptInputs
|
||||
|
||||
amt := btcutil.Amount(res.SelfOutputSignDesc.Output.Value)
|
||||
expectedReport := &channeldb.ResolverReport{
|
||||
OutPoint: wire.OutPoint{},
|
||||
Amount: amt,
|
||||
ResolverType: channeldb.ResolverTypeCommit,
|
||||
ResolverOutcome: channeldb.ResolverOutcomeClaimed,
|
||||
SpendTxID: &spendHash,
|
||||
}
|
||||
|
||||
assertResolverReport(t, reportChan, expectedReport)
|
||||
|
||||
ctx.waitForResult()
|
||||
}
|
||||
|
||||
@ -203,6 +234,21 @@ func testCommitSweepResolverDelay(t *testing.T, sweepErr error) {
|
||||
|
||||
ctx := newCommitSweepResolverTestContext(t, &res)
|
||||
|
||||
// Replace our checkpoint with one which will push reports into a
|
||||
// channel for us to consume. We replace this function on the resolver
|
||||
// itself because it is created by the test context.
|
||||
reportChan := make(chan *channeldb.ResolverReport)
|
||||
ctx.resolver.Checkpoint = func(_ ContractResolver,
|
||||
reports ...*channeldb.ResolverReport) error {
|
||||
|
||||
// Send all of our reports into the channel.
|
||||
for _, report := range reports {
|
||||
reportChan <- report
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Setup whether we expect the sweeper to receive a sweep error in this
|
||||
// test case.
|
||||
ctx.sweeper.sweepErr = sweepErr
|
||||
@ -250,6 +296,22 @@ func testCommitSweepResolverDelay(t *testing.T, sweepErr error) {
|
||||
|
||||
<-ctx.sweeper.sweptInputs
|
||||
|
||||
// Set the resolution report outcome based on whether our sweep
|
||||
// succeeded.
|
||||
outcome := channeldb.ResolverOutcomeClaimed
|
||||
if sweepErr != nil {
|
||||
outcome = channeldb.ResolverOutcomeUnclaimed
|
||||
}
|
||||
sweepTx := ctx.sweeper.sweepTx.TxHash()
|
||||
|
||||
assertResolverReport(t, reportChan, &channeldb.ResolverReport{
|
||||
OutPoint: outpoint,
|
||||
ResolverType: channeldb.ResolverTypeCommit,
|
||||
ResolverOutcome: outcome,
|
||||
Amount: btcutil.Amount(amt),
|
||||
SpendTxID: &sweepTx,
|
||||
})
|
||||
|
||||
ctx.waitForResult()
|
||||
|
||||
// If this test case generates a sweep error, we don't expect to be
|
||||
|
Loading…
Reference in New Issue
Block a user