Skip to content

Commit d8a4b37

Browse files
committed
contractcourt: persist commit sweep resolutions
1 parent d0ec872 commit d8a4b37

File tree

3 files changed

+84
-6
lines changed

3 files changed

+84
-6
lines changed

channeldb/reports.go

+4
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ const (
5555

5656
// ResolverTypeOutgoingHtlc represents resolution of an outgoing htlc.
5757
ResolverTypeOutgoingHtlc ResolverType = 2
58+
59+
// ResolverTypeCommit represents resolution of our time locked commit
60+
// when we force close.
61+
ResolverTypeCommit ResolverType = 3
5862
)
5963

6064
// ResolverOutcome indicates the outcome for the resolver that that the contract

contractcourt/commit_sweep_resolver.go

+17-5
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import (
66
"io"
77
"sync"
88

9+
"github.com/btcsuite/btcd/chaincfg/chainhash"
910
"github.com/btcsuite/btcd/txscript"
1011
"github.com/btcsuite/btcd/wire"
1112
"github.com/btcsuite/btcutil"
13+
"github.com/lightningnetwork/lnd/channeldb"
1214
"github.com/lightningnetwork/lnd/input"
1315
"github.com/lightningnetwork/lnd/lnwallet"
1416
"github.com/lightningnetwork/lnd/sweep"
@@ -235,11 +237,13 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
235237
return nil, err
236238
}
237239

240+
var sweepTxID chainhash.Hash
241+
238242
// Sweeper is going to join this input with other inputs if
239243
// possible and publish the sweep tx. When the sweep tx
240244
// confirms, it signals us through the result channel with the
241245
// outcome. Wait for this to happen.
242-
recovered := true
246+
outcome := channeldb.ResolverOutcomeClaimed
243247
select {
244248
case sweepResult := <-resultChan:
245249
switch sweepResult.Err {
@@ -250,7 +254,7 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
250254
// the contract.
251255
c.log.Warnf("local commitment output was swept by "+
252256
"remote party via %v", sweepResult.Tx.TxHash())
253-
recovered = false
257+
outcome = channeldb.ResolverOutcomeUnclaimed
254258
case nil:
255259
// No errors, therefore continue processing.
256260
c.log.Infof("local commitment output fully resolved by "+
@@ -262,22 +266,30 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
262266

263267
return nil, sweepResult.Err
264268
}
269+
270+
sweepTxID = sweepResult.Tx.TxHash()
271+
265272
case <-c.quit:
266273
return nil, errResolverShuttingDown
267274
}
268275

269276
// Funds have been swept and balance is no longer in limbo.
270277
c.reportLock.Lock()
271-
if recovered {
278+
if outcome == channeldb.ResolverOutcomeClaimed {
272279
// We only record the balance as recovered if it actually came
273280
// back to us.
274281
c.currentReport.RecoveredBalance = c.currentReport.LimboBalance
275282
}
276283
c.currentReport.LimboBalance = 0
277284
c.reportLock.Unlock()
278-
285+
report := c.currentReport.resolverReport(
286+
&sweepTxID, channeldb.ResolverTypeCommit, outcome,
287+
)
279288
c.resolved = true
280-
return nil, c.Checkpoint(c, nil)
289+
290+
// Checkpoint the resolver with a closure that will write the outcome
291+
// of the resolver and its sweep transaction to disk.
292+
return nil, c.Checkpoint(c, report)
281293
}
282294

283295
// Stop signals the resolver to cancel any current resolution processes, and

contractcourt/commit_sweep_resolver_test.go

+63-1
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,44 @@ func TestCommitSweepResolverNoDelay(t *testing.T) {
169169
}
170170

171171
ctx := newCommitSweepResolverTestContext(t, &res)
172+
173+
// Replace our checkpoint with one which will push reports into a
174+
// channel for us to consume. We replace this function on the resolver
175+
// itself because it is created by the test context.
176+
reportChan := make(chan *channeldb.ResolverReport)
177+
ctx.resolver.Checkpoint = func(_ ContractResolver,
178+
reports ...*channeldb.ResolverReport) error {
179+
180+
// Send all of our reports into the channel.
181+
for _, report := range reports {
182+
reportChan <- report
183+
}
184+
185+
return nil
186+
}
187+
172188
ctx.resolve()
173189

174-
ctx.notifier.confChan <- &chainntnfs.TxConfirmation{}
190+
spendTx := &wire.MsgTx{}
191+
spendHash := spendTx.TxHash()
192+
ctx.notifier.confChan <- &chainntnfs.TxConfirmation{
193+
Tx: spendTx,
194+
}
175195

176196
// No csv delay, so the input should be swept immediately.
177197
<-ctx.sweeper.sweptInputs
178198

199+
amt := btcutil.Amount(res.SelfOutputSignDesc.Output.Value)
200+
expectedReport := &channeldb.ResolverReport{
201+
OutPoint: wire.OutPoint{},
202+
Amount: amt,
203+
ResolverType: channeldb.ResolverTypeCommit,
204+
ResolverOutcome: channeldb.ResolverOutcomeClaimed,
205+
SpendTxID: &spendHash,
206+
}
207+
208+
assertResolverReport(t, reportChan, expectedReport)
209+
179210
ctx.waitForResult()
180211
}
181212

@@ -203,6 +234,21 @@ func testCommitSweepResolverDelay(t *testing.T, sweepErr error) {
203234

204235
ctx := newCommitSweepResolverTestContext(t, &res)
205236

237+
// Replace our checkpoint with one which will push reports into a
238+
// channel for us to consume. We replace this function on the resolver
239+
// itself because it is created by the test context.
240+
reportChan := make(chan *channeldb.ResolverReport)
241+
ctx.resolver.Checkpoint = func(_ ContractResolver,
242+
reports ...*channeldb.ResolverReport) error {
243+
244+
// Send all of our reports into the channel.
245+
for _, report := range reports {
246+
reportChan <- report
247+
}
248+
249+
return nil
250+
}
251+
206252
// Setup whether we expect the sweeper to receive a sweep error in this
207253
// test case.
208254
ctx.sweeper.sweepErr = sweepErr
@@ -250,6 +296,22 @@ func testCommitSweepResolverDelay(t *testing.T, sweepErr error) {
250296

251297
<-ctx.sweeper.sweptInputs
252298

299+
// Set the resolution report outcome based on whether our sweep
300+
// succeeded.
301+
outcome := channeldb.ResolverOutcomeClaimed
302+
if sweepErr != nil {
303+
outcome = channeldb.ResolverOutcomeUnclaimed
304+
}
305+
sweepTx := ctx.sweeper.sweepTx.TxHash()
306+
307+
assertResolverReport(t, reportChan, &channeldb.ResolverReport{
308+
OutPoint: outpoint,
309+
ResolverType: channeldb.ResolverTypeCommit,
310+
ResolverOutcome: outcome,
311+
Amount: btcutil.Amount(amt),
312+
SpendTxID: &sweepTx,
313+
})
314+
253315
ctx.waitForResult()
254316

255317
// If this test case generates a sweep error, we don't expect to be

0 commit comments

Comments
 (0)