github.com/decred/dcrlnd@v0.7.6/lntest/itest/lnd_hold_invoice_force_test.go (about) 1 package itest 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/decred/dcrlnd/lncfg" 8 "github.com/decred/dcrlnd/lnrpc" 9 "github.com/decred/dcrlnd/lnrpc/invoicesrpc" 10 "github.com/decred/dcrlnd/lnrpc/routerrpc" 11 "github.com/decred/dcrlnd/lntest" 12 "github.com/decred/dcrlnd/lntest/wait" 13 "github.com/decred/dcrlnd/lntypes" 14 "github.com/stretchr/testify/require" 15 ) 16 17 // testHoldInvoiceForceClose tests cancelation of accepted hold invoices which 18 // would otherwise trigger force closes when they expire. 19 func testHoldInvoiceForceClose(net *lntest.NetworkHarness, t *harnessTest) { 20 ctxb, cancel := context.WithCancel(context.Background()) 21 defer cancel() 22 23 // Open a channel between alice and bob. 24 chanReq := lntest.OpenChannelParams{ 25 Amt: 300000, 26 } 27 28 chanPoint := openChannelAndAssert( 29 t, net, net.Alice, net.Bob, chanReq, 30 ) 31 32 // Create a non-dust hold invoice for bob. 33 var ( 34 preimage = lntypes.Preimage{1, 2, 3} 35 payHash = preimage.Hash() 36 ) 37 invoiceReq := &invoicesrpc.AddHoldInvoiceRequest{ 38 Value: 30000, 39 CltvExpiry: 40, 40 Hash: payHash[:], 41 } 42 43 ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) 44 defer cancel() 45 bobInvoice, err := net.Bob.AddHoldInvoice(ctxt, invoiceReq) 46 require.NoError(t.t, err) 47 48 // Pay this invoice from Alice -> Bob, we should achieve this with a 49 // single htlc. 50 _, err = net.Alice.RouterClient.SendPaymentV2( 51 ctxb, &routerrpc.SendPaymentRequest{ 52 PaymentRequest: bobInvoice.PaymentRequest, 53 TimeoutSeconds: 60, 54 FeeLimitMAtoms: noFeeLimitMAtoms, 55 }, 56 ) 57 require.NoError(t.t, err) 58 59 waitForInvoiceAccepted(t, net.Bob, payHash) 60 61 // Once the HTLC has cleared, alice and bob should both have a single 62 // htlc locked in. 63 nodes := []*lntest.HarnessNode{net.Alice, net.Bob} 64 err = wait.NoError(func() error { 65 return assertActiveHtlcs(nodes, payHash[:]) 66 }, defaultTimeout) 67 require.NoError(t.t, err) 68 69 // Get our htlc expiry height and current block height so that we 70 // can mine the exact number of blocks required to expire the htlc. 71 chans, err := net.Alice.ListChannels(ctxb, &lnrpc.ListChannelsRequest{}) 72 require.NoError(t.t, err) 73 require.Len(t.t, chans.Channels, 1) 74 require.Len(t.t, chans.Channels[0].PendingHtlcs, 1) 75 activeHtlc := chans.Channels[0].PendingHtlcs[0] 76 77 require.NoError(t.t, net.Alice.WaitForBlockchainSync()) 78 require.NoError(t.t, net.Bob.WaitForBlockchainSync()) 79 80 info, err := net.Alice.GetInfo(ctxb, &lnrpc.GetInfoRequest{}) 81 require.NoError(t.t, err) 82 83 // Now we will mine blocks until the htlc expires, and wait for each 84 // node to sync to our latest height. Sanity check that we won't 85 // underflow. 86 require.Greater( 87 t.t, activeHtlc.ExpirationHeight, info.BlockHeight, 88 "expected expiry after current height", 89 ) 90 blocksTillExpiry := activeHtlc.ExpirationHeight - info.BlockHeight 91 92 // Alice will go to chain with some delta, sanity check that we won't 93 // underflow and subtract this from our mined blocks. 94 require.Greater( 95 t.t, blocksTillExpiry, 96 uint32(lncfg.DefaultOutgoingBroadcastDelta), 97 ) 98 blocksTillForce := blocksTillExpiry - lncfg.DefaultOutgoingBroadcastDelta 99 100 mineBlocksSlow(t, net, blocksTillForce, 0) 101 102 require.NoError(t.t, net.Alice.WaitForBlockchainSync()) 103 require.NoError(t.t, net.Bob.WaitForBlockchainSync()) 104 105 // Our channel should not have been force closed, instead we expect our 106 // channel to still be open and our invoice to have been canceled before 107 // expiry. 108 chanInfo, err := getChanInfo(net.Alice) 109 require.NoError(t.t, err) 110 111 fundingTxID, err := lnrpc.GetChanPointFundingTxid(chanPoint) 112 require.NoError(t.t, err) 113 chanStr := fmt.Sprintf("%v:%v", fundingTxID, chanPoint.OutputIndex) 114 require.Equal(t.t, chanStr, chanInfo.ChannelPoint) 115 116 err = wait.NoError(func() error { 117 inv, err := net.Bob.LookupInvoice(ctxt, &lnrpc.PaymentHash{ 118 RHash: payHash[:], 119 }) 120 if err != nil { 121 return err 122 } 123 124 if inv.State != lnrpc.Invoice_CANCELED { 125 return fmt.Errorf("expected canceled invoice, got: %v", 126 inv.State) 127 } 128 129 for _, htlc := range inv.Htlcs { 130 if htlc.State != lnrpc.InvoiceHTLCState_CANCELED { 131 return fmt.Errorf("expected htlc canceled, "+ 132 "got: %v", htlc.State) 133 } 134 } 135 136 return nil 137 }, defaultTimeout) 138 require.NoError(t.t, err, "expected canceled invoice") 139 140 // Clean up the channel. 141 closeChannelAndAssert(t, net, net.Alice, chanPoint, false) 142 }