mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
loop: fix loopout and client tests for sweeper integration
This commit is contained in:
parent
0914074b10
commit
33fdde949f
4 changed files with 173 additions and 56 deletions
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/lightninglabs/loop/loopdb"
|
||||
"github.com/lightninglabs/loop/swap"
|
||||
"github.com/lightninglabs/loop/test"
|
||||
"github.com/lightninglabs/loop/utils"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -146,8 +147,6 @@ func TestLoopOutFailWrongAmount(t *testing.T) {
|
|||
// TestLoopOutResume tests that swaps in various states are properly resumed
|
||||
// after a restart.
|
||||
func TestLoopOutResume(t *testing.T) {
|
||||
defer test.Guard(t)()
|
||||
|
||||
defaultConfs := loopdb.DefaultLoopOutHtlcConfirmations
|
||||
|
||||
storedVersion := []loopdb.ProtocolVersion{
|
||||
|
|
@ -279,7 +278,7 @@ func testLoopOutResume(t *testing.T, confs uint32, expired, preimageRevealed,
|
|||
preimageRevealed, int32(confs),
|
||||
)
|
||||
|
||||
htlc, err := GetHtlc(
|
||||
htlc, err := utils.GetHtlc(
|
||||
hash, &pendingSwap.Contract.SwapContract,
|
||||
&chaincfg.TestNet3Params,
|
||||
)
|
||||
|
|
@ -304,7 +303,7 @@ func testLoopOutResume(t *testing.T, confs uint32, expired, preimageRevealed,
|
|||
func(r error) {},
|
||||
func(r error) {},
|
||||
preimageRevealed,
|
||||
confIntent, GetHtlcScriptVersion(protocolVersion),
|
||||
confIntent, utils.GetHtlcScriptVersion(protocolVersion),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -317,15 +316,28 @@ func testLoopOutSuccess(ctx *testContext, amt btcutil.Amount, hash lntypes.Hash,
|
|||
|
||||
signalPrepaymentResult(nil)
|
||||
|
||||
ctx.AssertRegisterSpendNtfn(confIntent.PkScript)
|
||||
|
||||
// Assert that a call to track payment was sent, and respond with status
|
||||
// in flight so that our swap will push its preimage to the server.
|
||||
ctx.trackPayment(lnrpc.Payment_IN_FLIGHT)
|
||||
|
||||
// We need to notify the height, as the loopout is going to attempt a
|
||||
// sweep when a new block is received.
|
||||
err := ctx.Lnd.NotifyHeight(ctx.Lnd.Height + 1)
|
||||
require.NoError(ctx.Context.T, err)
|
||||
|
||||
// Publish tick.
|
||||
ctx.expiryChan <- testTime
|
||||
|
||||
// One spend notifier is registered by batch to watch primary sweep.
|
||||
ctx.AssertRegisterSpendNtfn(confIntent.PkScript)
|
||||
|
||||
ctx.AssertEpochListeners(2)
|
||||
|
||||
// Mock the blockheight again as that's when the batch will broadcast
|
||||
// the tx.
|
||||
err = ctx.Lnd.NotifyHeight(ctx.Lnd.Height + 1)
|
||||
require.NoError(ctx.Context.T, err)
|
||||
|
||||
// Expect a signing request in the non taproot case.
|
||||
if scriptVersion != swap.HtlcV3 {
|
||||
<-ctx.Context.Lnd.SignOutputRawChannel
|
||||
|
|
@ -341,13 +353,6 @@ func testLoopOutSuccess(ctx *testContext, amt btcutil.Amount, hash lntypes.Hash,
|
|||
// our MuSig2 signing attempts.
|
||||
if scriptVersion == swap.HtlcV3 {
|
||||
ctx.assertPreimagePush(ctx.store.LoopOutSwaps[hash].Preimage)
|
||||
|
||||
// Try MuSig2 signing first and fail it so that we go for a
|
||||
// normal sweep.
|
||||
for i := 0; i < maxMusigSweepRetries; i++ {
|
||||
ctx.expiryChan <- testTime
|
||||
ctx.assertPreimagePush(ctx.store.LoopOutSwaps[hash].Preimage)
|
||||
}
|
||||
<-ctx.Context.Lnd.SignOutputRawChannel
|
||||
}
|
||||
|
||||
|
|
@ -388,6 +393,8 @@ func testLoopOutSuccess(ctx *testContext, amt btcutil.Amount, hash lntypes.Hash,
|
|||
|
||||
ctx.NotifySpend(sweepTx, 0)
|
||||
|
||||
ctx.AssertRegisterConf(true, 3)
|
||||
|
||||
ctx.assertStatus(loopdb.StateSuccess)
|
||||
|
||||
ctx.assertStoreFinished(loopdb.StateSuccess)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightninglabs/loop/loopdb"
|
||||
"github.com/lightninglabs/loop/test"
|
||||
"github.com/lightninglabs/loop/utils"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
invpkg "github.com/lightningnetwork/lnd/invoices"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
|
|
@ -449,7 +450,7 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool,
|
|||
pendSwap.Loop.Events[0].Cost = cost
|
||||
}
|
||||
|
||||
htlc, err := GetHtlc(
|
||||
htlc, err := utils.GetHtlc(
|
||||
testPreimage.Hash(), &contract.SwapContract,
|
||||
cfg.lnd.ChainParams,
|
||||
)
|
||||
|
|
|
|||
164
loopout_test.go
164
loopout_test.go
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/lightninglabs/lndclient"
|
||||
"github.com/lightninglabs/loop/loopdb"
|
||||
"github.com/lightninglabs/loop/sweep"
|
||||
"github.com/lightninglabs/loop/sweepbatcher"
|
||||
"github.com/lightninglabs/loop/test"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
|
|
@ -293,13 +294,33 @@ func testCustomSweepConfTarget(t *testing.T) {
|
|||
return expiryChan
|
||||
}
|
||||
|
||||
errChan := make(chan error)
|
||||
errChan := make(chan error, 2)
|
||||
|
||||
batcherStore := sweepbatcher.NewStoreMock()
|
||||
|
||||
batcher := sweepbatcher.NewBatcher(
|
||||
lnd.WalletKit, lnd.ChainNotifier, lnd.Signer,
|
||||
mockMuSig2SignSweep, mockVerifySchnorrSigSuccess,
|
||||
lnd.ChainParams, batcherStore, cfg.store,
|
||||
)
|
||||
|
||||
tctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
go func() {
|
||||
err := swap.execute(context.Background(), &executeConfig{
|
||||
err := batcher.Run(tctx)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
err := swap.execute(tctx, &executeConfig{
|
||||
statusChan: statusChan,
|
||||
blockEpochChan: blockEpochChan,
|
||||
timerFactory: timerFactory,
|
||||
sweeper: sweeper,
|
||||
batcher: batcher,
|
||||
cancelSwap: server.CancelLoopOutSwap,
|
||||
verifySchnorrSig: mockVerifySchnorrSigFail,
|
||||
}, ctx.Lnd.Height)
|
||||
|
|
@ -335,16 +356,21 @@ func testCustomSweepConfTarget(t *testing.T) {
|
|||
|
||||
ctx.NotifyConf(htlcTx)
|
||||
|
||||
// The client should then register for a spend of the HTLC and attempt
|
||||
// to sweep it using the custom confirmation target.
|
||||
ctx.AssertRegisterSpendNtfn(swap.htlc.PkScript)
|
||||
|
||||
// Assert that we made a query to track our payment, as required for
|
||||
// preimage push tracking.
|
||||
trackPayment := ctx.AssertTrackPayment()
|
||||
|
||||
expiryChan <- time.Now()
|
||||
|
||||
// The client should then register for a spend of the HTLC and attempt
|
||||
// to sweep it using the custom confirmation target.
|
||||
ctx.AssertRegisterSpendNtfn(swap.htlc.PkScript)
|
||||
|
||||
ctx.AssertEpochListeners(1)
|
||||
|
||||
err = ctx.Lnd.NotifyHeight(ctx.Lnd.Height + 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Expect a signing request for the HTLC success transaction.
|
||||
if !IsTaprootSwap(&swap.SwapContract) {
|
||||
<-ctx.Lnd.SignOutputRawChannel
|
||||
|
|
@ -409,7 +435,7 @@ func testCustomSweepConfTarget(t *testing.T) {
|
|||
|
||||
// The sweep should have a fee that corresponds to the custom
|
||||
// confirmation target.
|
||||
_ = assertSweepTx(testReq.SweepConfTarget)
|
||||
sweepTx := assertSweepTx(testReq.SweepConfTarget)
|
||||
|
||||
// Once we have published an on chain sweep, we expect a preimage to
|
||||
// have been pushed to our server.
|
||||
|
|
@ -426,23 +452,13 @@ func testCustomSweepConfTarget(t *testing.T) {
|
|||
State: lnrpc.Payment_SUCCEEDED,
|
||||
}
|
||||
|
||||
// We'll then notify the height at which we begin using the default
|
||||
// confirmation target.
|
||||
defaultConfTargetHeight := ctx.Lnd.Height +
|
||||
testLoopOutMinOnChainCltvDelta - DefaultSweepConfTargetDelta
|
||||
blockEpochChan <- defaultConfTargetHeight
|
||||
expiryChan <- time.Now()
|
||||
|
||||
// Expect another signing request.
|
||||
<-ctx.Lnd.SignOutputRawChannel
|
||||
|
||||
// We should expect to see another sweep using the higher fee since the
|
||||
// spend hasn't been confirmed yet.
|
||||
sweepTx := assertSweepTx(DefaultSweepConfTarget)
|
||||
|
||||
// Notify the spend so that the swap reaches its final state.
|
||||
// Notify the batch for the spend.
|
||||
ctx.NotifySpend(sweepTx, 0)
|
||||
|
||||
// After receiving the notification the batch will start monitoring the
|
||||
// confirmations.
|
||||
ctx.AssertRegisterConf(true, 3)
|
||||
|
||||
cfg.store.(*loopdb.StoreMock).AssertLoopOutState(loopdb.StateSuccess)
|
||||
status = <-statusChan
|
||||
require.Equal(t, loopdb.StateSuccess, status.State)
|
||||
|
|
@ -511,13 +527,33 @@ func testPreimagePush(t *testing.T) {
|
|||
return expiryChan
|
||||
}
|
||||
|
||||
errChan := make(chan error)
|
||||
errChan := make(chan error, 2)
|
||||
|
||||
batcherStore := sweepbatcher.NewStoreMock()
|
||||
|
||||
batcher := sweepbatcher.NewBatcher(
|
||||
lnd.WalletKit, lnd.ChainNotifier, lnd.Signer,
|
||||
mockMuSig2SignSweep, mockVerifySchnorrSigSuccess,
|
||||
lnd.ChainParams, batcherStore, cfg.store,
|
||||
)
|
||||
|
||||
tctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
go func() {
|
||||
err := batcher.Run(tctx)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
err := swap.execute(context.Background(), &executeConfig{
|
||||
statusChan: statusChan,
|
||||
blockEpochChan: blockEpochChan,
|
||||
timerFactory: timerFactory,
|
||||
sweeper: sweeper,
|
||||
batcher: batcher,
|
||||
cancelSwap: server.CancelLoopOutSwap,
|
||||
verifySchnorrSig: mockVerifySchnorrSigFail,
|
||||
}, ctx.Lnd.Height)
|
||||
|
|
@ -553,10 +589,6 @@ func testPreimagePush(t *testing.T) {
|
|||
|
||||
ctx.NotifyConf(htlcTx)
|
||||
|
||||
// The client should then register for a spend of the HTLC and attempt
|
||||
// to sweep it using the custom confirmation target.
|
||||
ctx.AssertRegisterSpendNtfn(swap.htlc.PkScript)
|
||||
|
||||
// Assert that we made a query to track our payment, as required for
|
||||
// preimage push tracking.
|
||||
trackPayment := ctx.AssertTrackPayment()
|
||||
|
|
@ -567,6 +599,15 @@ func testPreimagePush(t *testing.T) {
|
|||
// preimage is not revealed, we also do not expect a preimage push.
|
||||
expiryChan <- testTime
|
||||
|
||||
// The client should then register for a spend of the HTLC and attempt
|
||||
// to sweep it using the custom confirmation target.
|
||||
ctx.AssertRegisterSpendNtfn(swap.htlc.PkScript)
|
||||
|
||||
ctx.AssertEpochListeners(1)
|
||||
|
||||
err = ctx.Lnd.NotifyHeight(ctx.Lnd.Height + 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
// When using taproot htlcs the flow is different as we do reveal the
|
||||
// preimage before sweeping in order for the server to trust us with
|
||||
// our MuSig2 signing attempts.
|
||||
|
|
@ -582,15 +623,6 @@ func testPreimagePush(t *testing.T) {
|
|||
preimage := <-server.preimagePush
|
||||
require.Equal(t, swap.Preimage, preimage)
|
||||
|
||||
// Try MuSig2 signing first and fail it so that we go for a
|
||||
// normal sweep.
|
||||
for i := 0; i < maxMusigSweepRetries; i++ {
|
||||
expiryChan <- time.Now()
|
||||
|
||||
preimage := <-server.preimagePush
|
||||
require.Equal(t, swap.Preimage, preimage)
|
||||
}
|
||||
|
||||
<-ctx.Lnd.SignOutputRawChannel
|
||||
|
||||
// We expect the sweep tx to have been published.
|
||||
|
|
@ -611,6 +643,10 @@ func testPreimagePush(t *testing.T) {
|
|||
// Now when we report a new block and tick our expiry fee timer, and
|
||||
// fees are acceptably low so we expect our sweep to be published.
|
||||
blockEpochChan <- ctx.Lnd.Height + 2
|
||||
|
||||
err = ctx.Lnd.NotifyHeight(ctx.Lnd.Height + 2)
|
||||
require.NoError(t, err)
|
||||
|
||||
expiryChan <- testTime
|
||||
|
||||
if IsTaprootSwap(&swap.SwapContract) {
|
||||
|
|
@ -648,6 +684,10 @@ func testPreimagePush(t *testing.T) {
|
|||
// chain yet so we can test our preimage push retry logic. Instead, we
|
||||
// tick the expiry chan again to prompt another sweep.
|
||||
expiryChan <- testTime
|
||||
|
||||
err = ctx.Lnd.NotifyHeight(ctx.Lnd.Height + 2)
|
||||
require.NoError(t, err)
|
||||
|
||||
if IsTaprootSwap(&swap.SwapContract) {
|
||||
preimage := <-server.preimagePush
|
||||
require.Equal(t, swap.Preimage, preimage)
|
||||
|
|
@ -678,6 +718,10 @@ func testPreimagePush(t *testing.T) {
|
|||
// push. The test's mocked preimage channel is un-buffered, so our test
|
||||
// would hang if we pushed the preimage here.
|
||||
expiryChan <- testTime
|
||||
|
||||
err = ctx.Lnd.NotifyHeight(ctx.Lnd.Height + 2)
|
||||
require.NoError(t, err)
|
||||
|
||||
<-ctx.Lnd.SignOutputRawChannel
|
||||
sweepTx := ctx.ReceiveTx()
|
||||
|
||||
|
|
@ -685,6 +729,10 @@ func testPreimagePush(t *testing.T) {
|
|||
// spend our sweepTx and assert that the swap succeeds.
|
||||
ctx.NotifySpend(sweepTx, 0)
|
||||
|
||||
// After receiving the spend ntfn the batch will start monitoring for
|
||||
// confs.
|
||||
ctx.AssertRegisterConf(true, 3)
|
||||
|
||||
cfg.store.(*loopdb.StoreMock).AssertLoopOutState(loopdb.StateSuccess)
|
||||
status := <-statusChan
|
||||
require.Equal(
|
||||
|
|
@ -892,8 +940,6 @@ func TestLoopOutMuSig2Sweep(t *testing.T) {
|
|||
return expiryChan
|
||||
}
|
||||
|
||||
errChan := make(chan error)
|
||||
|
||||
// Mock a successful signature verify to make sure we don't fail
|
||||
// creating the MuSig2 sweep.
|
||||
mockVerifySchnorrSigSuccess := func(pubKey *btcec.PublicKey, hash,
|
||||
|
|
@ -902,12 +948,33 @@ func TestLoopOutMuSig2Sweep(t *testing.T) {
|
|||
return nil
|
||||
}
|
||||
|
||||
errChan := make(chan error, 2)
|
||||
|
||||
batcherStore := sweepbatcher.NewStoreMock()
|
||||
|
||||
batcher := sweepbatcher.NewBatcher(
|
||||
lnd.WalletKit, lnd.ChainNotifier, lnd.Signer,
|
||||
mockMuSig2SignSweep, mockVerifySchnorrSigSuccess,
|
||||
lnd.ChainParams, batcherStore, cfg.store,
|
||||
)
|
||||
|
||||
tctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
go func() {
|
||||
err := batcher.Run(tctx)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
err := swap.execute(context.Background(), &executeConfig{
|
||||
statusChan: statusChan,
|
||||
blockEpochChan: blockEpochChan,
|
||||
timerFactory: timerFactory,
|
||||
sweeper: sweeper,
|
||||
batcher: batcher,
|
||||
cancelSwap: server.CancelLoopOutSwap,
|
||||
verifySchnorrSig: mockVerifySchnorrSigSuccess,
|
||||
}, ctx.Lnd.Height)
|
||||
|
|
@ -943,10 +1010,6 @@ func TestLoopOutMuSig2Sweep(t *testing.T) {
|
|||
|
||||
ctx.NotifyConf(htlcTx)
|
||||
|
||||
// The client should then register for a spend of the HTLC and attempt
|
||||
// to sweep it using the custom confirmation target.
|
||||
ctx.AssertRegisterSpendNtfn(swap.htlc.PkScript)
|
||||
|
||||
// Assert that we made a query to track our payment, as required for
|
||||
// preimage push tracking.
|
||||
trackPayment := ctx.AssertTrackPayment()
|
||||
|
|
@ -957,6 +1020,15 @@ func TestLoopOutMuSig2Sweep(t *testing.T) {
|
|||
// preimage is not revealed, we also do not expect a preimage push.
|
||||
expiryChan <- testTime
|
||||
|
||||
// The client should then register for a spend of the HTLC and attempt
|
||||
// to sweep it using the custom confirmation target.
|
||||
ctx.AssertRegisterSpendNtfn(swap.htlc.PkScript)
|
||||
|
||||
ctx.AssertEpochListeners(1)
|
||||
|
||||
err = ctx.Lnd.NotifyHeight(ctx.Lnd.Height + 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
// When using taproot htlcs the flow is different as we do reveal the
|
||||
// preimage before sweeping in order for the server to trust us with
|
||||
// our MuSig2 signing attempts.
|
||||
|
|
@ -988,6 +1060,10 @@ func TestLoopOutMuSig2Sweep(t *testing.T) {
|
|||
// Now when we report a new block and tick our expiry fee timer, and
|
||||
// fees are acceptably low so we expect our sweep to be published.
|
||||
blockEpochChan <- ctx.Lnd.Height + 2
|
||||
|
||||
err = ctx.Lnd.NotifyHeight(ctx.Lnd.Height + 2)
|
||||
require.NoError(t, err)
|
||||
|
||||
expiryChan <- testTime
|
||||
|
||||
preimage = <-server.preimagePush
|
||||
|
|
@ -1010,6 +1086,10 @@ func TestLoopOutMuSig2Sweep(t *testing.T) {
|
|||
// spend our sweepTx and assert that the swap succeeds.
|
||||
ctx.NotifySpend(sweepTx, 0)
|
||||
|
||||
// After receiving the spend ntfn the batch will start monitoring for
|
||||
// confs.
|
||||
ctx.AssertRegisterConf(true, 3)
|
||||
|
||||
cfg.store.(*loopdb.StoreMock).AssertLoopOutState(loopdb.StateSuccess)
|
||||
status = <-statusChan
|
||||
require.Equal(t, status.State, loopdb.StateSuccess)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/lightninglabs/loop/loopdb"
|
||||
"github.com/lightninglabs/loop/swap"
|
||||
"github.com/lightninglabs/loop/sweep"
|
||||
"github.com/lightninglabs/loop/sweepbatcher"
|
||||
"github.com/lightninglabs/loop/test"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
|
|
@ -51,6 +52,24 @@ func mockVerifySchnorrSigFail(pubKey *btcec.PublicKey, hash,
|
|||
return fmt.Errorf("invalid sig")
|
||||
}
|
||||
|
||||
// mockVerifySchnorrSigSuccess is used to simulate successful taproot keyspend
|
||||
// signature verification. If passed to the executeConfig we'll test an
|
||||
// uncooperative server and will fall back to scriptspend sweep.
|
||||
func mockVerifySchnorrSigSuccess(pubKey *btcec.PublicKey, hash,
|
||||
sig []byte) error {
|
||||
|
||||
return fmt.Errorf("invalid sig")
|
||||
}
|
||||
|
||||
func mockMuSig2SignSweep(ctx context.Context,
|
||||
protocolVersion loopdb.ProtocolVersion, swapHash lntypes.Hash,
|
||||
paymentAddr [32]byte, nonce []byte, sweepTxPsbt []byte,
|
||||
prevoutMap map[wire.OutPoint]*wire.TxOut) (
|
||||
[]byte, []byte, error) {
|
||||
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
func newSwapClient(config *clientConfig) *Client {
|
||||
sweeper := &sweep.Sweeper{
|
||||
Lnd: config.LndServices,
|
||||
|
|
@ -58,10 +77,20 @@ func newSwapClient(config *clientConfig) *Client {
|
|||
|
||||
lndServices := config.LndServices
|
||||
|
||||
batcherStore := sweepbatcher.NewStoreMock()
|
||||
|
||||
batcher := sweepbatcher.NewBatcher(
|
||||
config.LndServices.WalletKit, config.LndServices.ChainNotifier,
|
||||
config.LndServices.Signer, mockMuSig2SignSweep,
|
||||
mockVerifySchnorrSigSuccess, config.LndServices.ChainParams,
|
||||
batcherStore, config.Store,
|
||||
)
|
||||
|
||||
executor := newExecutor(&executorConfig{
|
||||
lnd: lndServices,
|
||||
store: config.Store,
|
||||
sweeper: sweeper,
|
||||
batcher: batcher,
|
||||
createExpiryTimer: config.CreateExpiryTimer,
|
||||
cancelSwap: config.Server.CancelLoopOutSwap,
|
||||
verifySchnorrSig: mockVerifySchnorrSigFail,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue