contractcourt: test sweep of locally breached commit tx
This adds a test to the commit sweeper resolver to ensure it behaves properly if the local node breaches a channel. In this situation the remote party is expected to sweep the breached output to itself and therefore the local party won't be able to recover any funds.
This commit is contained in:
parent
d71a4ee033
commit
2110bfa40b
@ -96,6 +96,7 @@ func (i *commitSweepResolverTestContext) waitForResult() {
|
||||
type mockSweeper struct {
|
||||
sweptInputs chan input.Input
|
||||
updatedInputs chan wire.OutPoint
|
||||
sweepErr error
|
||||
}
|
||||
|
||||
func newMockSweeper() *mockSweeper {
|
||||
@ -112,7 +113,8 @@ func (s *mockSweeper) SweepInput(input input.Input, params sweep.Params) (
|
||||
|
||||
result := make(chan sweep.Result, 1)
|
||||
result <- sweep.Result{
|
||||
Tx: &wire.MsgTx{},
|
||||
Tx: &wire.MsgTx{},
|
||||
Err: s.sweepErr,
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@ -244,3 +246,92 @@ func TestCommitSweepResolverDelay(t *testing.T) {
|
||||
t.Fatal("unexpected resolver report")
|
||||
}
|
||||
}
|
||||
|
||||
// TestCommitSweepResolverLocalBreach tests resolution when the local node
|
||||
// publishes a breached output (one that is swept by the remote party).
|
||||
func TestCommitSweepResolverLocalBreach(t *testing.T) {
|
||||
t.Parallel()
|
||||
defer timeout(t)()
|
||||
|
||||
amt := int64(100)
|
||||
outpoint := wire.OutPoint{
|
||||
Index: 5,
|
||||
}
|
||||
res := lnwallet.CommitOutputResolution{
|
||||
SelfOutputSignDesc: input.SignDescriptor{
|
||||
Output: &wire.TxOut{
|
||||
Value: amt,
|
||||
},
|
||||
WitnessScript: []byte{0},
|
||||
},
|
||||
MaturityDelay: 3,
|
||||
SelfOutPoint: outpoint,
|
||||
}
|
||||
|
||||
ctx := newCommitSweepResolverTestContext(t, &res)
|
||||
|
||||
// Setup the sweeper so that it returns an error of the output being
|
||||
// already swept.
|
||||
ctx.sweeper.sweepErr = sweep.ErrRemoteSpend
|
||||
|
||||
report := ctx.resolver.report()
|
||||
expectedReport := ContractReport{
|
||||
Outpoint: outpoint,
|
||||
Type: ReportOutputUnencumbered,
|
||||
Amount: btcutil.Amount(amt),
|
||||
LimboBalance: btcutil.Amount(amt),
|
||||
}
|
||||
if *report != expectedReport {
|
||||
t.Fatalf("unexpected resolver report. want=%v got=%v",
|
||||
expectedReport, report)
|
||||
}
|
||||
|
||||
ctx.resolve()
|
||||
|
||||
ctx.notifier.confChan <- &chainntnfs.TxConfirmation{
|
||||
BlockHeight: testInitialBlockHeight - 1,
|
||||
}
|
||||
|
||||
// Allow resolver to process confirmation.
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// Expect report to be updated.
|
||||
report = ctx.resolver.report()
|
||||
if report.MaturityHeight != testInitialBlockHeight+2 {
|
||||
t.Fatal("report maturity height incorrect")
|
||||
}
|
||||
|
||||
// Notify initial block height. The csv lock is still in effect, so we
|
||||
// don't expect any sweep to happen yet.
|
||||
ctx.notifyEpoch(testInitialBlockHeight)
|
||||
|
||||
select {
|
||||
case <-ctx.sweeper.sweptInputs:
|
||||
t.Fatal("no sweep expected")
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
}
|
||||
|
||||
// A new block arrives. The commit tx confirmed at height -1 and the csv
|
||||
// is 3, so a spend will be valid in the first block after height +1.
|
||||
ctx.notifyEpoch(testInitialBlockHeight + 1)
|
||||
|
||||
<-ctx.sweeper.sweptInputs
|
||||
|
||||
ctx.waitForResult()
|
||||
|
||||
report = ctx.resolver.report()
|
||||
expectedReport = ContractReport{
|
||||
Outpoint: outpoint,
|
||||
Type: ReportOutputUnencumbered,
|
||||
Amount: btcutil.Amount(amt),
|
||||
MaturityHeight: testInitialBlockHeight + 2,
|
||||
|
||||
// RecoveredBalance is zero due to the output having been swept
|
||||
// by the remote party.
|
||||
RecoveredBalance: 0,
|
||||
}
|
||||
if *report != expectedReport {
|
||||
t.Fatalf("unexpected resolver report. want=%v got=%v",
|
||||
expectedReport, report)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user