@@ -581,3 +581,117 @@ func TestPreimagePush(t *testing.T) {
581581
582582 require .NoError (t , <- errChan )
583583}
584+
585+ // TestExpiryBeforeReveal tests the case where the on-chain HTLC expires before
586+ // we have revealed our preimage. This test demonstrates that the client will
587+ // erroneously reveal the preimage even though we're nearing our timeout.
588+ func TestExpiryBeforeReveal (t * testing.T ) {
589+ defer test .Guard (t )()
590+
591+ lnd := test .NewMockLnd ()
592+ ctx := test .NewContext (t , lnd )
593+ server := newServerMock (lnd )
594+
595+ testReq := * testRequest
596+
597+ // Set on-chain HTLC CLTV.
598+ testReq .Expiry = ctx .Lnd .Height + testLoopOutMinOnChainCltvDelta
599+
600+ // Set our fee estimate to higher than our max miner fee will allow.
601+ lnd .SetFeeEstimate (testReq .SweepConfTarget , chainfee .SatPerKWeight (
602+ testReq .MaxMinerFee * 2 ,
603+ ))
604+
605+ // Setup the cfg using mock server and init a loop out request.
606+ cfg := newSwapConfig (
607+ & lnd .LndServices , newStoreMock (t ), server ,
608+ )
609+ initResult , err := newLoopOutSwap (
610+ context .Background (), cfg , ctx .Lnd .Height , & testReq ,
611+ )
612+ require .NoError (t , err )
613+ swap := initResult .swap
614+
615+ // Set up the required dependencies to execute the swap.
616+ sweeper := & sweep.Sweeper {Lnd : & lnd .LndServices }
617+ blockEpochChan := make (chan interface {})
618+ statusChan := make (chan SwapInfo )
619+ expiryChan := make (chan time.Time )
620+ timerFactory := func (_ time.Duration ) <- chan time.Time {
621+ return expiryChan
622+ }
623+
624+ errChan := make (chan error )
625+ cancelCtx , cancel := context .WithCancel (context .Background ())
626+ go func () {
627+ err := swap .execute (cancelCtx , & executeConfig {
628+ statusChan : statusChan ,
629+ blockEpochChan : blockEpochChan ,
630+ timerFactory : timerFactory ,
631+ sweeper : sweeper ,
632+ }, ctx .Lnd .Height )
633+ if err != nil {
634+ log .Error (err )
635+ }
636+ errChan <- err
637+ }()
638+
639+ // The swap should be found in its initial state.
640+ cfg .store .(* storeMock ).assertLoopOutStored ()
641+ state := <- statusChan
642+ require .Equal (t , loopdb .StateInitiated , state .State )
643+
644+ // We'll then pay both the swap and prepay invoice, which should trigger
645+ // the server to publish the on-chain HTLC.
646+ signalSwapPaymentResult := ctx .AssertPaid (swapInvoiceDesc )
647+ signalPrepaymentResult := ctx .AssertPaid (prepayInvoiceDesc )
648+
649+ signalSwapPaymentResult (nil )
650+ signalPrepaymentResult (nil )
651+
652+ // Notify the confirmation notification for the HTLC.
653+ ctx .AssertRegisterConf (false , defaultConfirmations )
654+
655+ // Advance the block height to get the HTLC confirmed.
656+ blockEpochChan <- ctx .Lnd .Height + 1
657+
658+ htlcTx := wire .NewMsgTx (2 )
659+ htlcTx .AddTxOut (& wire.TxOut {
660+ Value : int64 (swap .AmountRequested ),
661+ PkScript : swap .htlc .PkScript ,
662+ })
663+ ctx .NotifyConf (htlcTx )
664+
665+ // The client should then register for a spend of the HTLC and attempt
666+ // to sweep it using the custom confirmation target.
667+ ctx .AssertRegisterSpendNtfn (swap .htlc .PkScript )
668+
669+ // Assert that we made a query to track our payment, as required for
670+ // preimage push tracking.
671+ ctx .AssertTrackPayment ()
672+
673+ // Tick the expiry channel. Because our max miner fee is too high, we
674+ // won't attempt a sweep at this point.
675+ expiryChan <- testTime
676+
677+ // Now we decrease our conf target to less than our max miner fee.
678+ lnd .SetFeeEstimate (testReq .SweepConfTarget , chainfee .SatPerKWeight (
679+ testReq .MaxMinerFee / 2 ,
680+ ))
681+
682+ // Advance the block height to the point where we would do timeout
683+ // instead of pushing the preimage.
684+ blockEpochChan <- lnd .Height + testReq .Expiry
685+
686+ // Tick our expiry chan again, this time we expect the swap to
687+ // publish our sweep timeout, despite expiry having passed, and the
688+ // potential for a race with the server.
689+ expiryChan <- testTime
690+
691+ // Expect a signing request for the HTLC success transaction.
692+ <- ctx .Lnd .SignOutputRawChannel
693+
694+ // We just cancel the swap now rather than testing to completion.
695+ cancel ()
696+ require .Equal (t , context .Canceled , <- errChan )
697+ }
0 commit comments