breacharbiter test: add TestBreachSecondLevelTransfer
This commit is contained in:
parent
60d9ae02c7
commit
e0560741b4
@ -20,6 +20,7 @@ import (
|
||||
|
||||
"github.com/btcsuite/btclog"
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
@ -1149,6 +1150,117 @@ func TestBreachHandoffFail(t *testing.T) {
|
||||
assertArbiterBreach(t, brar, chanPoint)
|
||||
}
|
||||
|
||||
// TestBreachSecondLevelTransfer tests that sweep of a HTLC output on a
|
||||
// breached commitment is transferred to a second level spend if the output is
|
||||
// already spent.
|
||||
func TestBreachSecondLevelTransfer(t *testing.T) {
|
||||
brar, alice, _, bobClose, contractBreaches,
|
||||
cleanUpChans, cleanUpArb := initBreachedState(t)
|
||||
defer cleanUpChans()
|
||||
defer cleanUpArb()
|
||||
|
||||
var (
|
||||
height = bobClose.ChanSnapshot.CommitHeight
|
||||
forceCloseTx = bobClose.CloseTx
|
||||
chanPoint = alice.ChanPoint
|
||||
publTx = make(chan *wire.MsgTx)
|
||||
publErr error
|
||||
)
|
||||
|
||||
// Make PublishTransaction always return ErrDoubleSpend to begin with.
|
||||
publErr = lnwallet.ErrDoubleSpend
|
||||
brar.cfg.PublishTransaction = func(tx *wire.MsgTx) error {
|
||||
publTx <- tx
|
||||
return publErr
|
||||
}
|
||||
|
||||
// Notify the breach arbiter about the breach.
|
||||
retribution, err := lnwallet.NewBreachRetribution(
|
||||
alice.State(), height, forceCloseTx, 1)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create breach retribution: %v", err)
|
||||
}
|
||||
|
||||
breach := &ContractBreachEvent{
|
||||
ChanPoint: *chanPoint,
|
||||
ProcessACK: make(chan error, 1),
|
||||
BreachRetribution: retribution,
|
||||
}
|
||||
contractBreaches <- breach
|
||||
|
||||
// We'll also wait to consume the ACK back from the breach arbiter.
|
||||
select {
|
||||
case err := <-breach.ProcessACK:
|
||||
if err != nil {
|
||||
t.Fatalf("handoff failed: %v", err)
|
||||
}
|
||||
case <-time.After(time.Second * 15):
|
||||
t.Fatalf("breach arbiter didn't send ack back")
|
||||
}
|
||||
|
||||
// After exiting, the breach arbiter should have persisted the
|
||||
// retribution information and the channel should be shown as pending
|
||||
// force closed.
|
||||
assertArbiterBreach(t, brar, chanPoint)
|
||||
|
||||
// Notify that the breaching transaction is confirmed, to trigger the
|
||||
// retribution logic.
|
||||
notifier := brar.cfg.Notifier.(*mockSpendNotifier)
|
||||
notifier.confChannel <- &chainntnfs.TxConfirmation{}
|
||||
|
||||
// The breach arbiter should attempt to sweep all outputs on the
|
||||
// breached commitment. We'll pretend that the HTLC output has been
|
||||
// spent by the channel counter party's second level tx already.
|
||||
var tx *wire.MsgTx
|
||||
select {
|
||||
case tx = <-publTx:
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatalf("tx was not published")
|
||||
}
|
||||
|
||||
if tx.TxIn[0].PreviousOutPoint.Hash != forceCloseTx.TxHash() {
|
||||
t.Fatalf("tx not attempting to spend commitment")
|
||||
}
|
||||
|
||||
// Find the index of the TxIn spending the HTLC output.
|
||||
htlcOutpoint := &retribution.HtlcRetributions[0].OutPoint
|
||||
htlcIn := -1
|
||||
for i, txIn := range tx.TxIn {
|
||||
if txIn.PreviousOutPoint == *htlcOutpoint {
|
||||
htlcIn = i
|
||||
}
|
||||
}
|
||||
if htlcIn == -1 {
|
||||
t.Fatalf("htlc in not found")
|
||||
}
|
||||
|
||||
// Since publishing the transaction failed above, the breach arbiter
|
||||
// will attempt another second level check. Now notify that the htlc
|
||||
// output is spent by a second level tx.
|
||||
secondLvlTx := &wire.MsgTx{
|
||||
TxOut: []*wire.TxOut{
|
||||
&wire.TxOut{Value: 1},
|
||||
},
|
||||
}
|
||||
notifier.Spend(htlcOutpoint, 2, secondLvlTx)
|
||||
|
||||
// Now a transaction attempting to spend from the second level tx
|
||||
// should be published instead. Let this publish succeed by setting the
|
||||
// publishing error to nil.
|
||||
publErr = nil
|
||||
select {
|
||||
case tx = <-publTx:
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatalf("tx was not published")
|
||||
}
|
||||
|
||||
// The TxIn previously attempting to spend the HTLC outpoint should now
|
||||
// be spending from the second level tx.
|
||||
if tx.TxIn[htlcIn].PreviousOutPoint.Hash != secondLvlTx.TxHash() {
|
||||
t.Fatalf("tx not attempting to spend second level tx, %v", tx.TxIn[0])
|
||||
}
|
||||
}
|
||||
|
||||
// assertArbiterBreach checks that the breach arbiter has persisted the breach
|
||||
// information for a particular channel.
|
||||
func assertArbiterBreach(t *testing.T, brar *breachArbiter,
|
||||
|
Loading…
Reference in New Issue
Block a user