github.com/decred/dcrlnd@v0.7.6/lntest/itest/lnd_channel_balance_test.go (about) 1 package itest 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/decred/dcrd/dcrutil/v4" 8 "github.com/decred/dcrlnd/chainreg" 9 "github.com/decred/dcrlnd/lnrpc" 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/lnwire" 14 "github.com/stretchr/testify/require" 15 ) 16 17 // testChannelBalance creates a new channel between Alice and Bob, then checks 18 // channel balance to be equal amount specified while creation of channel. 19 func testChannelBalance(net *lntest.NetworkHarness, t *harnessTest) { 20 // Open a channel with 0.16 DCR between Alice and Bob, ensuring the 21 // channel has been opened properly. 22 amount := defaultChanAmt 23 24 // Creates a helper closure to be used below which asserts the proper 25 // response to a channel balance RPC. 26 checkChannelBalance := func(node *lntest.HarnessNode, 27 local, remote dcrutil.Amount) { 28 29 expectedResponse := &lnrpc.ChannelBalanceResponse{ 30 LocalBalance: &lnrpc.Amount{ 31 Atoms: uint64(local), 32 Matoms: uint64(lnwire.NewMAtomsFromAtoms(local)), 33 }, 34 RemoteBalance: &lnrpc.Amount{ 35 Atoms: uint64(remote), 36 Matoms: uint64(lnwire.NewMAtomsFromAtoms( 37 remote, 38 )), 39 }, 40 UnsettledLocalBalance: &lnrpc.Amount{}, 41 UnsettledRemoteBalance: &lnrpc.Amount{}, 42 PendingOpenLocalBalance: &lnrpc.Amount{}, 43 PendingOpenRemoteBalance: &lnrpc.Amount{}, 44 // Deprecated fields. 45 Balance: int64(local), 46 } 47 assertChannelBalanceResp(t, node, expectedResponse) 48 } 49 50 // Before beginning, make sure alice and bob are connected. 51 net.EnsureConnected(t.t, net.Alice, net.Bob) 52 53 chanPoint := openChannelAndAssert( 54 t, net, net.Alice, net.Bob, 55 lntest.OpenChannelParams{ 56 Amt: amount, 57 }, 58 ) 59 60 // Wait for both Alice and Bob to recognize this new channel. 61 err := net.Alice.WaitForNetworkChannelOpen(chanPoint) 62 if err != nil { 63 t.Fatalf("alice didn't advertise channel before "+ 64 "timeout: %v", err) 65 } 66 err = net.Bob.WaitForNetworkChannelOpen(chanPoint) 67 if err != nil { 68 t.Fatalf("bob didn't advertise channel before "+ 69 "timeout: %v", err) 70 } 71 72 cType, err := channelCommitType(net.Alice, chanPoint) 73 if err != nil { 74 t.Fatalf("unable to get channel type: %v", err) 75 } 76 77 // As this is a single funder channel, Alice's balance should be 78 // exactly 0.5 DCR since now state transitions have taken place yet. 79 checkChannelBalance(net.Alice, amount-calcStaticFee(cType, 0), 0) 80 81 // Ensure Bob currently has no available balance within the channel. 82 checkChannelBalance(net.Bob, 0, amount-calcStaticFee(cType, 0)) 83 84 // Finally close the channel between Alice and Bob, asserting that the 85 // channel has been properly closed on-chain. 86 closeChannelAndAssert(t, net, net.Alice, chanPoint, false) 87 } 88 89 // testChannelUnsettledBalance will test that the UnsettledBalance field 90 // is updated according to the number of Pending Htlcs. 91 // Alice will send Htlcs to Carol while she is in hodl mode. This will result 92 // in a build of pending Htlcs. We expect the channels unsettled balance to 93 // equal the sum of all the Pending Htlcs. 94 func testChannelUnsettledBalance(net *lntest.NetworkHarness, t *harnessTest) { 95 const chanAmt = dcrutil.Amount(1000000) 96 ctxb := context.Background() 97 98 // Creates a helper closure to be used below which asserts the proper 99 // response to a channel balance RPC. 100 checkChannelBalance := func(node *lntest.HarnessNode, 101 local, remote, unsettledLocal, unsettledRemote dcrutil.Amount) { 102 103 expectedResponse := &lnrpc.ChannelBalanceResponse{ 104 LocalBalance: &lnrpc.Amount{ 105 Atoms: uint64(local), 106 Matoms: uint64(lnwire.NewMAtomsFromAtoms( 107 local, 108 )), 109 }, 110 RemoteBalance: &lnrpc.Amount{ 111 Atoms: uint64(remote), 112 Matoms: uint64(lnwire.NewMAtomsFromAtoms( 113 remote, 114 )), 115 }, 116 UnsettledLocalBalance: &lnrpc.Amount{ 117 Atoms: uint64(unsettledLocal), 118 Matoms: uint64(lnwire.NewMAtomsFromAtoms( 119 unsettledLocal, 120 )), 121 }, 122 UnsettledRemoteBalance: &lnrpc.Amount{ 123 Atoms: uint64(unsettledRemote), 124 Matoms: uint64(lnwire.NewMAtomsFromAtoms( 125 unsettledRemote, 126 )), 127 }, 128 PendingOpenLocalBalance: &lnrpc.Amount{}, 129 PendingOpenRemoteBalance: &lnrpc.Amount{}, 130 // Deprecated fields. 131 Balance: int64(local), 132 } 133 assertChannelBalanceResp(t, node, expectedResponse) 134 } 135 136 // Create carol in hodl mode. 137 carol := net.NewNode(t.t, "Carol", []string{"--hodl.exit-settle"}) 138 defer shutdownAndAssert(net, t, carol) 139 140 // Connect Alice to Carol. 141 net.ConnectNodes(t.t, net.Alice, carol) 142 143 // Open a channel between Alice and Carol. 144 chanPointAlice := openChannelAndAssert( 145 t, net, net.Alice, carol, 146 lntest.OpenChannelParams{ 147 Amt: chanAmt, 148 }, 149 ) 150 151 // Wait for Alice and Carol to receive the channel edge from the 152 // funding manager. 153 err := net.Alice.WaitForNetworkChannelOpen(chanPointAlice) 154 if err != nil { 155 t.Fatalf("alice didn't see the alice->carol channel before "+ 156 "timeout: %v", err) 157 } 158 159 err = carol.WaitForNetworkChannelOpen(chanPointAlice) 160 if err != nil { 161 t.Fatalf("alice didn't see the alice->carol channel before "+ 162 "timeout: %v", err) 163 } 164 165 cType, err := channelCommitType(net.Alice, chanPointAlice) 166 require.NoError(t.t, err, "unable to get channel type") 167 168 // Check alice's channel balance, which should have zero remote and zero 169 // pending balance. 170 checkChannelBalance(net.Alice, chanAmt-calcStaticFee(cType, 0), 0, 0, 0) 171 172 // Check carol's channel balance, which should have zero local and zero 173 // pending balance. 174 checkChannelBalance(carol, 0, chanAmt-calcStaticFee(cType, 0), 0, 0) 175 176 // Channel should be ready for payments. 177 const ( 178 payAmt = 100 179 numInvoices = 6 180 ) 181 182 // Simulateneously send numInvoices payments from Alice to Carol. 183 carolPubKey := carol.PubKey[:] 184 errChan := make(chan error) 185 for i := 0; i < numInvoices; i++ { 186 go func() { 187 ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) 188 _, err := net.Alice.RouterClient.SendPaymentV2(ctxt, 189 &routerrpc.SendPaymentRequest{ 190 Dest: carolPubKey, 191 Amt: int64(payAmt), 192 PaymentHash: makeFakePayHash(t), 193 FinalCltvDelta: chainreg.DefaultDecredTimeLockDelta, 194 TimeoutSeconds: 60, 195 FeeLimitMAtoms: noFeeLimitMAtoms, 196 }) 197 198 if err != nil { 199 errChan <- err 200 } 201 }() 202 } 203 204 // Test that the UnsettledBalance for both Alice and Carol 205 // is equal to the amount of invoices * payAmt. 206 var unsettledErr error 207 nodes := []*lntest.HarnessNode{net.Alice, carol} 208 err = wait.Predicate(func() bool { 209 // There should be a number of PendingHtlcs equal 210 // to the amount of Invoices sent. 211 unsettledErr = assertNumActiveHtlcs(nodes, numInvoices) 212 if unsettledErr != nil { 213 return false 214 } 215 216 // Set the amount expected for the Unsettled Balance for 217 // this channel. 218 expectedBalance := numInvoices * payAmt 219 220 // Check each nodes UnsettledBalance field. 221 for _, node := range nodes { 222 // Get channel info for the node. 223 chanInfo, err := getChanInfo(node) 224 if err != nil { 225 unsettledErr = err 226 return false 227 } 228 229 // Check that UnsettledBalance is what we expect. 230 if int(chanInfo.UnsettledBalance) != expectedBalance { 231 unsettledErr = fmt.Errorf("unsettled balance failed "+ 232 "expected: %v, received: %v", expectedBalance, 233 chanInfo.UnsettledBalance) 234 return false 235 } 236 } 237 238 return true 239 }, defaultTimeout) 240 if err != nil { 241 t.Fatalf("unsettled balace error: %v", unsettledErr) 242 } 243 244 // Check for payment errors. 245 select { 246 case err := <-errChan: 247 t.Fatalf("payment error: %v", err) 248 default: 249 } 250 251 // Check alice's channel balance, which should have a remote unsettled 252 // balance that equals to the amount of invoices * payAmt. The remote 253 // balance remains zero. 254 aliceLocal := chanAmt - calcStaticFee(cType, 0) - numInvoices*payAmt 255 checkChannelBalance(net.Alice, aliceLocal, 0, 0, numInvoices*payAmt) 256 257 // Check carol's channel balance, which should have a local unsettled 258 // balance that equals to the amount of invoices * payAmt. The local 259 // balance remains zero. 260 checkChannelBalance(carol, 0, aliceLocal, numInvoices*payAmt, 0) 261 262 // Force and assert the channel closure. 263 closeChannelAndAssert(t, net, net.Alice, chanPointAlice, true) 264 265 // Cleanup by mining the force close and sweep transaction. 266 cleanupForceClose(t, net, net.Alice, chanPointAlice) 267 }