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  }