contractcourt: test commitment deadline logic
This commit adds two tests to check that a) the correct deadline is used given different HTLC sets and b) when sweeping anchors the correct deadlines are used.
This commit is contained in:
parent
0dc3190fec
commit
614884dcb8
@ -7,6 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -2095,6 +2096,254 @@ func TestRemoteCloseInitiator(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestFindCommitmentDeadline tests the logic used to determine confirmation
|
||||||
|
// deadline is implemented as expected.
|
||||||
|
func TestFindCommitmentDeadline(t *testing.T) {
|
||||||
|
// Create a testing channel arbitrator.
|
||||||
|
log := &mockArbitratorLog{
|
||||||
|
state: StateDefault,
|
||||||
|
newStates: make(chan ArbitratorState, 5),
|
||||||
|
}
|
||||||
|
chanArbCtx, err := createTestChannelArbitrator(t, log)
|
||||||
|
require.NoError(t, err, "unable to create ChannelArbitrator")
|
||||||
|
|
||||||
|
// Add a dummy payment hash to the preimage lookup.
|
||||||
|
rHash := [lntypes.PreimageSize]byte{1, 2, 3}
|
||||||
|
mockPreimageDB := newMockWitnessBeacon()
|
||||||
|
mockPreimageDB.lookupPreimage[rHash] = rHash
|
||||||
|
|
||||||
|
// Attack a mock PreimageDB and Registry to channel arbitrator.
|
||||||
|
chanArb := chanArbCtx.chanArb
|
||||||
|
chanArb.cfg.PreimageDB = mockPreimageDB
|
||||||
|
chanArb.cfg.Registry = &mockRegistry{}
|
||||||
|
|
||||||
|
htlcIndexBase := uint64(99)
|
||||||
|
heightHint := uint32(1000)
|
||||||
|
htlcExpiryBase := heightHint + uint32(10)
|
||||||
|
|
||||||
|
// Create four testing HTLCs.
|
||||||
|
htlcDust := channeldb.HTLC{
|
||||||
|
HtlcIndex: htlcIndexBase + 1,
|
||||||
|
RefundTimeout: htlcExpiryBase + 1,
|
||||||
|
OutputIndex: -1,
|
||||||
|
}
|
||||||
|
htlcSmallExipry := channeldb.HTLC{
|
||||||
|
HtlcIndex: htlcIndexBase + 2,
|
||||||
|
RefundTimeout: htlcExpiryBase + 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
htlcPreimage := channeldb.HTLC{
|
||||||
|
HtlcIndex: htlcIndexBase + 3,
|
||||||
|
RefundTimeout: htlcExpiryBase + 3,
|
||||||
|
RHash: rHash,
|
||||||
|
}
|
||||||
|
htlcLargeExpiry := channeldb.HTLC{
|
||||||
|
HtlcIndex: htlcIndexBase + 4,
|
||||||
|
RefundTimeout: htlcExpiryBase + 100,
|
||||||
|
}
|
||||||
|
htlcExpired := channeldb.HTLC{
|
||||||
|
HtlcIndex: htlcIndexBase + 5,
|
||||||
|
RefundTimeout: heightHint,
|
||||||
|
}
|
||||||
|
|
||||||
|
makeHTLCSet := func(incoming, outgoing channeldb.HTLC) htlcSet {
|
||||||
|
return htlcSet{
|
||||||
|
incomingHTLCs: map[uint64]channeldb.HTLC{
|
||||||
|
incoming.HtlcIndex: incoming,
|
||||||
|
},
|
||||||
|
outgoingHTLCs: map[uint64]channeldb.HTLC{
|
||||||
|
outgoing.HtlcIndex: outgoing,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
htlcs htlcSet
|
||||||
|
err error
|
||||||
|
deadline uint32
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// When we have no HTLCs, the default value should be
|
||||||
|
// used.
|
||||||
|
name: "use default conf target",
|
||||||
|
htlcs: htlcSet{},
|
||||||
|
err: nil,
|
||||||
|
deadline: anchorSweepConfTarget,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// When we have a preimage available in the local HTLC
|
||||||
|
// set, its CLTV should be used.
|
||||||
|
name: "use htlc with preimage available",
|
||||||
|
htlcs: makeHTLCSet(htlcPreimage, htlcLargeExpiry),
|
||||||
|
err: nil,
|
||||||
|
deadline: htlcPreimage.RefundTimeout - heightHint,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// When the HTLC in the local set is not preimage
|
||||||
|
// available, we should not use its CLTV even its value
|
||||||
|
// is smaller.
|
||||||
|
name: "use htlc with no preimage available",
|
||||||
|
htlcs: makeHTLCSet(htlcSmallExipry, htlcLargeExpiry),
|
||||||
|
err: nil,
|
||||||
|
deadline: htlcLargeExpiry.RefundTimeout - heightHint,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// When we have dust HTLCs, their CLTVs should NOT be
|
||||||
|
// used even the values are smaller.
|
||||||
|
name: "ignore dust HTLCs",
|
||||||
|
htlcs: makeHTLCSet(htlcPreimage, htlcDust),
|
||||||
|
err: nil,
|
||||||
|
deadline: htlcPreimage.RefundTimeout - heightHint,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// When we've reached our deadline, use conf target of
|
||||||
|
// 1 as our deadline.
|
||||||
|
name: "use conf target 1",
|
||||||
|
htlcs: makeHTLCSet(htlcPreimage, htlcExpired),
|
||||||
|
err: nil,
|
||||||
|
deadline: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
tc := tc
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
deadline, err := chanArb.findCommitmentDeadline(
|
||||||
|
heightHint, tc.htlcs,
|
||||||
|
)
|
||||||
|
|
||||||
|
require.Equal(t, tc.err, err)
|
||||||
|
require.Equal(t, tc.deadline, deadline)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestSweepAnchors checks the sweep transactions are created using the
|
||||||
|
// expected deadlines for different anchor resolutions.
|
||||||
|
func TestSweepAnchors(t *testing.T) {
|
||||||
|
// Create a testing channel arbitrator.
|
||||||
|
log := &mockArbitratorLog{
|
||||||
|
state: StateDefault,
|
||||||
|
newStates: make(chan ArbitratorState, 5),
|
||||||
|
}
|
||||||
|
chanArbCtx, err := createTestChannelArbitrator(t, log)
|
||||||
|
require.NoError(t, err, "unable to create ChannelArbitrator")
|
||||||
|
|
||||||
|
// Add a dummy payment hash to the preimage lookup.
|
||||||
|
rHash := [lntypes.PreimageSize]byte{1, 2, 3}
|
||||||
|
mockPreimageDB := newMockWitnessBeacon()
|
||||||
|
mockPreimageDB.lookupPreimage[rHash] = rHash
|
||||||
|
|
||||||
|
// Attack a mock PreimageDB and Registry to channel arbitrator.
|
||||||
|
chanArb := chanArbCtx.chanArb
|
||||||
|
chanArb.cfg.PreimageDB = mockPreimageDB
|
||||||
|
chanArb.cfg.Registry = &mockRegistry{}
|
||||||
|
|
||||||
|
// Set current block height.
|
||||||
|
heightHint := uint32(1000)
|
||||||
|
chanArbCtx.chanArb.blocks <- int32(heightHint)
|
||||||
|
|
||||||
|
htlcIndexBase := uint64(99)
|
||||||
|
htlcExpiryBase := heightHint + uint32(10)
|
||||||
|
|
||||||
|
// Create three testing HTLCs.
|
||||||
|
htlcDust := channeldb.HTLC{
|
||||||
|
HtlcIndex: htlcIndexBase + 1,
|
||||||
|
RefundTimeout: htlcExpiryBase + 1,
|
||||||
|
OutputIndex: -1,
|
||||||
|
}
|
||||||
|
htlcWithPreimage := channeldb.HTLC{
|
||||||
|
HtlcIndex: htlcIndexBase + 2,
|
||||||
|
RefundTimeout: htlcExpiryBase + 2,
|
||||||
|
RHash: rHash,
|
||||||
|
}
|
||||||
|
htlcSmallExipry := channeldb.HTLC{
|
||||||
|
HtlcIndex: htlcIndexBase + 3,
|
||||||
|
RefundTimeout: htlcExpiryBase + 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup our local HTLC set such that we will use the HTLC's CLTV from
|
||||||
|
// the incoming HTLC set.
|
||||||
|
expectedLocalDeadline := htlcWithPreimage.RefundTimeout - heightHint
|
||||||
|
chanArb.activeHTLCs[LocalHtlcSet] = htlcSet{
|
||||||
|
incomingHTLCs: map[uint64]channeldb.HTLC{
|
||||||
|
htlcWithPreimage.HtlcIndex: htlcWithPreimage,
|
||||||
|
},
|
||||||
|
outgoingHTLCs: map[uint64]channeldb.HTLC{
|
||||||
|
htlcDust.HtlcIndex: htlcDust,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup our remote HTLC set such that no valid HTLCs can be used, thus
|
||||||
|
// we default to anchorSweepConfTarget.
|
||||||
|
expectedRemoteDeadline := anchorSweepConfTarget
|
||||||
|
chanArb.activeHTLCs[RemoteHtlcSet] = htlcSet{
|
||||||
|
incomingHTLCs: map[uint64]channeldb.HTLC{
|
||||||
|
htlcSmallExipry.HtlcIndex: htlcSmallExipry,
|
||||||
|
},
|
||||||
|
outgoingHTLCs: map[uint64]channeldb.HTLC{
|
||||||
|
htlcDust.HtlcIndex: htlcDust,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup out pending remote HTLC set such that we will use the HTLC's
|
||||||
|
// CLTV from the outgoing HTLC set.
|
||||||
|
expectedPendingDeadline := htlcSmallExipry.RefundTimeout - heightHint
|
||||||
|
chanArb.activeHTLCs[RemotePendingHtlcSet] = htlcSet{
|
||||||
|
incomingHTLCs: map[uint64]channeldb.HTLC{
|
||||||
|
htlcDust.HtlcIndex: htlcDust,
|
||||||
|
},
|
||||||
|
outgoingHTLCs: map[uint64]channeldb.HTLC{
|
||||||
|
htlcSmallExipry.HtlcIndex: htlcSmallExipry,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create AnchorResolutions.
|
||||||
|
anchors := &lnwallet.AnchorResolutions{
|
||||||
|
Local: &lnwallet.AnchorResolution{
|
||||||
|
AnchorSignDescriptor: input.SignDescriptor{
|
||||||
|
Output: &wire.TxOut{Value: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Remote: &lnwallet.AnchorResolution{
|
||||||
|
AnchorSignDescriptor: input.SignDescriptor{
|
||||||
|
Output: &wire.TxOut{Value: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RemotePending: &lnwallet.AnchorResolution{
|
||||||
|
AnchorSignDescriptor: input.SignDescriptor{
|
||||||
|
Output: &wire.TxOut{Value: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sweep anchors and check there's no error.
|
||||||
|
err = chanArb.sweepAnchors(anchors, heightHint)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Verify deadlines are used as expected.
|
||||||
|
deadlines := chanArbCtx.sweeper.deadlines
|
||||||
|
// Since there's no guarantee of the deadline orders, we sort it here
|
||||||
|
// so they can be compared.
|
||||||
|
sort.Ints(deadlines) // [12, 13, 144]
|
||||||
|
require.EqualValues(
|
||||||
|
t, expectedLocalDeadline, deadlines[0],
|
||||||
|
"local deadline not matched",
|
||||||
|
)
|
||||||
|
require.EqualValues(
|
||||||
|
t, expectedPendingDeadline, deadlines[1],
|
||||||
|
"pending remote deadline not matched",
|
||||||
|
)
|
||||||
|
require.EqualValues(
|
||||||
|
t, expectedRemoteDeadline, deadlines[2],
|
||||||
|
"remote deadline not matched",
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// TestChannelArbitratorAnchors asserts that the commitment tx anchor is swept.
|
// TestChannelArbitratorAnchors asserts that the commitment tx anchor is swept.
|
||||||
func TestChannelArbitratorAnchors(t *testing.T) {
|
func TestChannelArbitratorAnchors(t *testing.T) {
|
||||||
log := &mockArbitratorLog{
|
log := &mockArbitratorLog{
|
||||||
|
@ -109,7 +109,7 @@ type mockSweeper struct {
|
|||||||
sweepErr error
|
sweepErr error
|
||||||
createSweepTxChan chan *wire.MsgTx
|
createSweepTxChan chan *wire.MsgTx
|
||||||
|
|
||||||
deadlines []uint32
|
deadlines []int
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMockSweeper() *mockSweeper {
|
func newMockSweeper() *mockSweeper {
|
||||||
@ -118,7 +118,7 @@ func newMockSweeper() *mockSweeper {
|
|||||||
updatedInputs: make(chan wire.OutPoint),
|
updatedInputs: make(chan wire.OutPoint),
|
||||||
sweepTx: &wire.MsgTx{},
|
sweepTx: &wire.MsgTx{},
|
||||||
createSweepTxChan: make(chan *wire.MsgTx),
|
createSweepTxChan: make(chan *wire.MsgTx),
|
||||||
deadlines: []uint32{},
|
deadlines: []int{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ func (s *mockSweeper) SweepInput(input input.Input, params sweep.Params) (
|
|||||||
|
|
||||||
// Update the deadlines used if it's set.
|
// Update the deadlines used if it's set.
|
||||||
if params.Fee.ConfTarget != 0 {
|
if params.Fee.ConfTarget != 0 {
|
||||||
s.deadlines = append(s.deadlines, params.Fee.ConfTarget)
|
s.deadlines = append(s.deadlines, int(params.Fee.ConfTarget))
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make(chan sweep.Result, 1)
|
result := make(chan sweep.Result, 1)
|
||||||
|
Loading…
Reference in New Issue
Block a user