Merge pull request #4512 from yyforyongyu/channel-balance-verbose
display verbose result in ChannelBalance
This commit is contained in:
7 files changed
+1340
-961
No files matched your search
+966
-851
File diff suppressed because it is too large.
Load diff
+33
-6
@@ -32,8 +32,9 @@ service Lightning {
|
|||||||
rpc WalletBalance (WalletBalanceRequest) returns (WalletBalanceResponse);
|
rpc WalletBalance (WalletBalanceRequest) returns (WalletBalanceResponse);
|
||||||
|
|
||||||
/* lncli: `channelbalance`
|
/* lncli: `channelbalance`
|
||||||
ChannelBalance returns the total funds available across all open channels
|
ChannelBalance returns a report on the total funds across all open channels,
|
||||||
in satoshis.
|
categorized in local/remote, pending local/remote and unsettled local/remote
|
||||||
|
balances.
|
||||||
*/
|
*/
|
||||||
rpc ChannelBalance (ChannelBalanceRequest) returns (ChannelBalanceResponse);
|
rpc ChannelBalance (ChannelBalanceRequest) returns (ChannelBalanceResponse);
|
||||||
|
|
||||||
@@ -2133,14 +2134,40 @@ message WalletBalanceResponse {
|
|||||||
int64 unconfirmed_balance = 3;
|
int64 unconfirmed_balance = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message Amount {
|
||||||
|
// Value denominated in satoshis.
|
||||||
|
uint64 sat = 1;
|
||||||
|
|
||||||
|
// Value denominated in milli-satoshis.
|
||||||
|
uint64 msat = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message ChannelBalanceRequest {
|
message ChannelBalanceRequest {
|
||||||
}
|
}
|
||||||
message ChannelBalanceResponse {
|
message ChannelBalanceResponse {
|
||||||
// Sum of channels balances denominated in satoshis
|
// Deprecated. Sum of channels balances denominated in satoshis
|
||||||
int64 balance = 1;
|
int64 balance = 1 [deprecated = true];
|
||||||
|
|
||||||
// Sum of channels pending balances denominated in satoshis
|
// Deprecated. Sum of channels pending balances denominated in satoshis
|
||||||
int64 pending_open_balance = 2;
|
int64 pending_open_balance = 2 [deprecated = true];
|
||||||
|
|
||||||
|
// Sum of channels local balances.
|
||||||
|
Amount local_balance = 3;
|
||||||
|
|
||||||
|
// Sum of channels remote balances.
|
||||||
|
Amount remote_balance = 4;
|
||||||
|
|
||||||
|
// Sum of channels local unsettled balances.
|
||||||
|
Amount unsettled_local_balance = 5;
|
||||||
|
|
||||||
|
// Sum of channels remote unsettled balances.
|
||||||
|
Amount unsettled_remote_balance = 6;
|
||||||
|
|
||||||
|
// Sum of channels pending local balances.
|
||||||
|
Amount pending_open_local_balance = 7;
|
||||||
|
|
||||||
|
// Sum of channels pending remote balances.
|
||||||
|
Amount pending_open_remote_balance = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
message QueryRoutesRequest {
|
message QueryRoutesRequest {
|
||||||
|
|||||||
+42
-3
@@ -36,7 +36,7 @@
|
|||||||
},
|
},
|
||||||
"/v1/balance/channels": {
|
"/v1/balance/channels": {
|
||||||
"get": {
|
"get": {
|
||||||
"summary": "lncli: `channelbalance`\nChannelBalance returns the total funds available across all open channels\nin satoshis.",
|
"summary": "lncli: `channelbalance`\nChannelBalance returns a report on the total funds across all open channels,\ncategorized in local/remote, pending local/remote and unsettled local/remote\nbalances.",
|
||||||
"operationId": "ChannelBalance",
|
"operationId": "ChannelBalance",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
@@ -2476,6 +2476,21 @@
|
|||||||
"description": "- `p2wkh`: Pay to witness key hash (`WITNESS_PUBKEY_HASH` = 0)\n- `np2wkh`: Pay to nested witness key hash (`NESTED_PUBKEY_HASH` = 1)",
|
"description": "- `p2wkh`: Pay to witness key hash (`WITNESS_PUBKEY_HASH` = 0)\n- `np2wkh`: Pay to nested witness key hash (`NESTED_PUBKEY_HASH` = 1)",
|
||||||
"title": "`AddressType` has to be one of:"
|
"title": "`AddressType` has to be one of:"
|
||||||
},
|
},
|
||||||
|
"lnrpcAmount": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"sat": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uint64",
|
||||||
|
"description": "Value denominated in satoshis."
|
||||||
|
},
|
||||||
|
"msat": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uint64",
|
||||||
|
"description": "Value denominated in milli-satoshis."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"lnrpcBakeMacaroonRequest": {
|
"lnrpcBakeMacaroonRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -2813,12 +2828,36 @@
|
|||||||
"balance": {
|
"balance": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "int64",
|
"format": "int64",
|
||||||
"title": "Sum of channels balances denominated in satoshis"
|
"title": "Deprecated. Sum of channels balances denominated in satoshis"
|
||||||
},
|
},
|
||||||
"pending_open_balance": {
|
"pending_open_balance": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "int64",
|
"format": "int64",
|
||||||
"title": "Sum of channels pending balances denominated in satoshis"
|
"title": "Deprecated. Sum of channels pending balances denominated in satoshis"
|
||||||
|
},
|
||||||
|
"local_balance": {
|
||||||
|
"$ref": "#/definitions/lnrpcAmount",
|
||||||
|
"description": "Sum of channels local balances."
|
||||||
|
},
|
||||||
|
"remote_balance": {
|
||||||
|
"$ref": "#/definitions/lnrpcAmount",
|
||||||
|
"description": "Sum of channels remote balances."
|
||||||
|
},
|
||||||
|
"unsettled_local_balance": {
|
||||||
|
"$ref": "#/definitions/lnrpcAmount",
|
||||||
|
"description": "Sum of channels local unsettled balances."
|
||||||
|
},
|
||||||
|
"unsettled_remote_balance": {
|
||||||
|
"$ref": "#/definitions/lnrpcAmount",
|
||||||
|
"description": "Sum of channels remote unsettled balances."
|
||||||
|
},
|
||||||
|
"pending_open_local_balance": {
|
||||||
|
"$ref": "#/definitions/lnrpcAmount",
|
||||||
|
"description": "Sum of channels pending local balances."
|
||||||
|
},
|
||||||
|
"pending_open_remote_balance": {
|
||||||
|
"$ref": "#/definitions/lnrpcAmount",
|
||||||
|
"description": "Sum of channels pending remote balances."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -42,25 +42,48 @@ func testHtlcErrorPropagation(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
|
|
||||||
commitFee := cType.calcStaticFee(0)
|
commitFee := cType.calcStaticFee(0)
|
||||||
assertBaseBalance := func() {
|
assertBaseBalance := func() {
|
||||||
balReq := &lnrpc.ChannelBalanceRequest{}
|
// Alice has opened a channel with Bob with zero push amount, so
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
// it's remote balance is zero.
|
||||||
aliceBal, err := net.Alice.ChannelBalance(ctxt, balReq)
|
expBalanceAlice := &lnrpc.ChannelBalanceResponse{
|
||||||
if err != nil {
|
LocalBalance: &lnrpc.Amount{
|
||||||
t.Fatalf("unable to get channel balance: %v", err)
|
Sat: uint64(chanAmt - commitFee),
|
||||||
|
Msat: uint64(lnwire.NewMSatFromSatoshis(
|
||||||
|
chanAmt - commitFee,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
RemoteBalance: &lnrpc.Amount{},
|
||||||
|
UnsettledLocalBalance: &lnrpc.Amount{},
|
||||||
|
UnsettledRemoteBalance: &lnrpc.Amount{},
|
||||||
|
PendingOpenLocalBalance: &lnrpc.Amount{},
|
||||||
|
PendingOpenRemoteBalance: &lnrpc.Amount{},
|
||||||
|
// Deprecated fields.
|
||||||
|
Balance: int64(chanAmt - commitFee),
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
assertChannelBalanceResp(t, net.Alice, expBalanceAlice)
|
||||||
bobBal, err := net.Bob.ChannelBalance(ctxt, balReq)
|
|
||||||
if err != nil {
|
// Bob has a channel with Alice and another with Carol, so it's
|
||||||
t.Fatalf("unable to get channel balance: %v", err)
|
// local and remote balances are both chanAmt - commitFee.
|
||||||
}
|
expBalanceBob := &lnrpc.ChannelBalanceResponse{
|
||||||
if aliceBal.Balance != int64(chanAmt-commitFee) {
|
LocalBalance: &lnrpc.Amount{
|
||||||
t.Fatalf("alice has an incorrect balance: expected %v got %v",
|
Sat: uint64(chanAmt - commitFee),
|
||||||
int64(chanAmt-commitFee), aliceBal)
|
Msat: uint64(lnwire.NewMSatFromSatoshis(
|
||||||
}
|
chanAmt - commitFee,
|
||||||
if bobBal.Balance != int64(chanAmt-commitFee) {
|
)),
|
||||||
t.Fatalf("bob has an incorrect balance: expected %v got %v",
|
},
|
||||||
int64(chanAmt-commitFee), bobBal)
|
RemoteBalance: &lnrpc.Amount{
|
||||||
|
Sat: uint64(chanAmt - commitFee),
|
||||||
|
Msat: uint64(lnwire.NewMSatFromSatoshis(
|
||||||
|
chanAmt - commitFee,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
UnsettledLocalBalance: &lnrpc.Amount{},
|
||||||
|
UnsettledRemoteBalance: &lnrpc.Amount{},
|
||||||
|
PendingOpenLocalBalance: &lnrpc.Amount{},
|
||||||
|
PendingOpenRemoteBalance: &lnrpc.Amount{},
|
||||||
|
// Deprecated fields.
|
||||||
|
Balance: int64(chanAmt - commitFee),
|
||||||
}
|
}
|
||||||
|
assertChannelBalanceResp(t, net.Bob, expBalanceBob)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since we'd like to test some multi-hop failure scenarios, we'll
|
// Since we'd like to test some multi-hop failure scenarios, we'll
|
||||||
@@ -174,7 +197,6 @@ out:
|
|||||||
// an unknown payment hash.
|
// an unknown payment hash.
|
||||||
// TODO(roasbeef): return failure response rather than failing entire
|
// TODO(roasbeef): return failure response rather than failing entire
|
||||||
// stream on payment error.
|
// stream on payment error.
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
sendReq := &routerrpc.SendPaymentRequest{
|
sendReq := &routerrpc.SendPaymentRequest{
|
||||||
PaymentHash: makeFakePayHash(t),
|
PaymentHash: makeFakePayHash(t),
|
||||||
Dest: carol.PubKey[:],
|
Dest: carol.PubKey[:],
|
||||||
|
|||||||
@@ -301,7 +301,7 @@ func testPsbtChanFunding(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to get carol's balance: %v", err)
|
t.Fatalf("unable to get carol's balance: %v", err)
|
||||||
}
|
}
|
||||||
if balRes.Balance == 0 {
|
if balRes.LocalBalance.Sat == 0 {
|
||||||
t.Fatalf("carol has an empty channel balance")
|
t.Fatalf("carol has an empty channel balance")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+198
-73
@@ -1096,6 +1096,31 @@ func channelCommitType(node *lntest.HarnessNode,
|
|||||||
return 0, fmt.Errorf("channel point %v not found", chanPoint)
|
return 0, fmt.Errorf("channel point %v not found", chanPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// assertChannelBalanceResp makes a ChannelBalance request and checks the
|
||||||
|
// returned response matches the expected.
|
||||||
|
func assertChannelBalanceResp(t *harnessTest,
|
||||||
|
node *lntest.HarnessNode, expected *lnrpc.ChannelBalanceResponse) {
|
||||||
|
|
||||||
|
resp := getChannelBalance(t, node)
|
||||||
|
require.Equal(
|
||||||
|
t.t, expected, resp, "balance is incorrect",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getChannelBalance gets the channel balance.
|
||||||
|
func getChannelBalance(t *harnessTest,
|
||||||
|
node *lntest.HarnessNode) *lnrpc.ChannelBalanceResponse {
|
||||||
|
|
||||||
|
t.t.Helper()
|
||||||
|
|
||||||
|
ctxt, _ := context.WithTimeout(context.Background(), defaultTimeout)
|
||||||
|
req := &lnrpc.ChannelBalanceRequest{}
|
||||||
|
resp, err := node.ChannelBalance(ctxt, req)
|
||||||
|
|
||||||
|
require.NoError(t.t, err, "unable to get node's balance")
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
// basicChannelFundingTest is a sub-test of the main testBasicChannelFunding
|
// basicChannelFundingTest is a sub-test of the main testBasicChannelFunding
|
||||||
// test. Given two nodes: Alice and Bob, it'll assert proper channel creation,
|
// test. Given two nodes: Alice and Bob, it'll assert proper channel creation,
|
||||||
// then return a function closure that should be called to assert proper
|
// then return a function closure that should be called to assert proper
|
||||||
@@ -1107,6 +1132,31 @@ func basicChannelFundingTest(t *harnessTest, net *lntest.NetworkHarness,
|
|||||||
chanAmt := lnd.MaxBtcFundingAmount
|
chanAmt := lnd.MaxBtcFundingAmount
|
||||||
pushAmt := btcutil.Amount(100000)
|
pushAmt := btcutil.Amount(100000)
|
||||||
|
|
||||||
|
// Record nodes' channel balance before testing.
|
||||||
|
aliceChannelBalance := getChannelBalance(t, alice)
|
||||||
|
bobChannelBalance := getChannelBalance(t, bob)
|
||||||
|
|
||||||
|
// Creates a helper closure to be used below which asserts the proper
|
||||||
|
// response to a channel balance RPC.
|
||||||
|
checkChannelBalance := func(node *lntest.HarnessNode,
|
||||||
|
oldChannelBalance *lnrpc.ChannelBalanceResponse,
|
||||||
|
local, remote btcutil.Amount) {
|
||||||
|
|
||||||
|
newResp := oldChannelBalance
|
||||||
|
|
||||||
|
newResp.LocalBalance.Sat += uint64(local)
|
||||||
|
newResp.LocalBalance.Msat += uint64(
|
||||||
|
lnwire.NewMSatFromSatoshis(local),
|
||||||
|
)
|
||||||
|
newResp.RemoteBalance.Sat += uint64(remote)
|
||||||
|
newResp.RemoteBalance.Msat += uint64(
|
||||||
|
lnwire.NewMSatFromSatoshis(remote),
|
||||||
|
)
|
||||||
|
// Deprecated fields.
|
||||||
|
newResp.Balance += int64(local)
|
||||||
|
assertChannelBalanceResp(t, node, newResp)
|
||||||
|
}
|
||||||
|
|
||||||
// First establish a channel with a capacity of 0.5 BTC between Alice
|
// First establish a channel with a capacity of 0.5 BTC between Alice
|
||||||
// and Bob with Alice pushing 100k satoshis to Bob's side during
|
// and Bob with Alice pushing 100k satoshis to Bob's side during
|
||||||
// funding. This function will block until the channel itself is fully
|
// funding. This function will block until the channel itself is fully
|
||||||
@@ -1144,33 +1194,13 @@ func basicChannelFundingTest(t *harnessTest, net *lntest.NetworkHarness,
|
|||||||
|
|
||||||
// With the channel open, ensure that the amount specified above has
|
// With the channel open, ensure that the amount specified above has
|
||||||
// properly been pushed to Bob.
|
// properly been pushed to Bob.
|
||||||
balReq := &lnrpc.ChannelBalanceRequest{}
|
aliceLocalBalance := chanAmt - pushAmt - cType.calcStaticFee(0)
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
checkChannelBalance(
|
||||||
aliceBal, err := alice.ChannelBalance(ctxt, balReq)
|
alice, aliceChannelBalance, aliceLocalBalance, pushAmt,
|
||||||
if err != nil {
|
)
|
||||||
return nil, nil, nil, fmt.Errorf("unable to get alice's "+
|
checkChannelBalance(
|
||||||
"balance: %v", err)
|
bob, bobChannelBalance, pushAmt, aliceLocalBalance,
|
||||||
}
|
)
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
bobBal, err := bob.ChannelBalance(ctxt, balReq)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, fmt.Errorf("unable to get bobs's "+
|
|
||||||
"balance: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expBalanceAlice := chanAmt - pushAmt - cType.calcStaticFee(0)
|
|
||||||
aliceBalance := btcutil.Amount(aliceBal.Balance)
|
|
||||||
if aliceBalance != expBalanceAlice {
|
|
||||||
return nil, nil, nil, fmt.Errorf("alice's balance is "+
|
|
||||||
"incorrect: expected %v got %v",
|
|
||||||
expBalanceAlice, aliceBalance)
|
|
||||||
}
|
|
||||||
|
|
||||||
bobBalance := btcutil.Amount(bobBal.Balance)
|
|
||||||
if bobBalance != pushAmt {
|
|
||||||
return nil, nil, nil, fmt.Errorf("bob's balance is incorrect: "+
|
|
||||||
"expected %v got %v", pushAmt, bobBalance)
|
|
||||||
}
|
|
||||||
|
|
||||||
req := &lnrpc.ListChannelsRequest{}
|
req := &lnrpc.ListChannelsRequest{}
|
||||||
aliceChannel, err := alice.ListChannels(context.Background(), req)
|
aliceChannel, err := alice.ListChannels(context.Background(), req)
|
||||||
@@ -1405,6 +1435,58 @@ func testUnconfirmedChannelFunding(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Creates a helper closure to be used below which asserts the proper
|
||||||
|
// response to a channel balance RPC.
|
||||||
|
checkChannelBalance := func(node *lntest.HarnessNode,
|
||||||
|
local, remote, pendingLocal, pendingRemote btcutil.Amount) {
|
||||||
|
expectedResponse := &lnrpc.ChannelBalanceResponse{
|
||||||
|
LocalBalance: &lnrpc.Amount{
|
||||||
|
Sat: uint64(local),
|
||||||
|
Msat: uint64(lnwire.NewMSatFromSatoshis(
|
||||||
|
local,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
RemoteBalance: &lnrpc.Amount{
|
||||||
|
Sat: uint64(remote),
|
||||||
|
Msat: uint64(lnwire.NewMSatFromSatoshis(
|
||||||
|
remote,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
PendingOpenLocalBalance: &lnrpc.Amount{
|
||||||
|
Sat: uint64(pendingLocal),
|
||||||
|
Msat: uint64(lnwire.NewMSatFromSatoshis(
|
||||||
|
pendingLocal,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
PendingOpenRemoteBalance: &lnrpc.Amount{
|
||||||
|
Sat: uint64(pendingRemote),
|
||||||
|
Msat: uint64(lnwire.NewMSatFromSatoshis(
|
||||||
|
pendingRemote,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
UnsettledLocalBalance: &lnrpc.Amount{},
|
||||||
|
UnsettledRemoteBalance: &lnrpc.Amount{},
|
||||||
|
// Deprecated fields.
|
||||||
|
Balance: int64(local),
|
||||||
|
PendingOpenBalance: int64(pendingLocal),
|
||||||
|
}
|
||||||
|
assertChannelBalanceResp(t, node, expectedResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
// As the channel is pending open, it's expected Carol has both zero
|
||||||
|
// local and remote balances, and pending local/remote should not be
|
||||||
|
// zero.
|
||||||
|
//
|
||||||
|
// Note that atm we haven't obtained the chanPoint yet, so we use the
|
||||||
|
// type directly.
|
||||||
|
cType := commitTypeTweakless
|
||||||
|
carolLocalBalance := chanAmt - pushAmt - cType.calcStaticFee(0)
|
||||||
|
checkChannelBalance(carol, 0, 0, carolLocalBalance, pushAmt)
|
||||||
|
|
||||||
|
// For Alice, her local/remote balances should be zero, and the
|
||||||
|
// local/remote balances are the mirror of Carol's.
|
||||||
|
checkChannelBalance(net.Alice, 0, 0, pushAmt, carolLocalBalance)
|
||||||
|
|
||||||
// Confirm the channel and wait for it to be recognized by both
|
// Confirm the channel and wait for it to be recognized by both
|
||||||
// parties. Two transactions should be mined, the unconfirmed spend and
|
// parties. Two transactions should be mined, the unconfirmed spend and
|
||||||
// the funding tx.
|
// the funding tx.
|
||||||
@@ -1415,32 +1497,10 @@ func testUnconfirmedChannelFunding(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
t.Fatalf("error while waiting for channel open: %v", err)
|
t.Fatalf("error while waiting for channel open: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cType, err := channelCommitType(net.Alice, chanPoint)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to get channel type: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// With the channel open, we'll check the balances on each side of the
|
// With the channel open, we'll check the balances on each side of the
|
||||||
// channel as a sanity check to ensure things worked out as intended.
|
// channel as a sanity check to ensure things worked out as intended.
|
||||||
balReq := &lnrpc.ChannelBalanceRequest{}
|
checkChannelBalance(carol, carolLocalBalance, pushAmt, 0, 0)
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
checkChannelBalance(net.Alice, pushAmt, carolLocalBalance, 0, 0)
|
||||||
carolBal, err := carol.ChannelBalance(ctxt, balReq)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to get carol's balance: %v", err)
|
|
||||||
}
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
aliceBal, err := net.Alice.ChannelBalance(ctxt, balReq)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to get alice's balance: %v", err)
|
|
||||||
}
|
|
||||||
if carolBal.Balance != int64(chanAmt-pushAmt-cType.calcStaticFee(0)) {
|
|
||||||
t.Fatalf("carol's balance is incorrect: expected %v got %v",
|
|
||||||
chanAmt-pushAmt-cType.calcStaticFee(0), carolBal)
|
|
||||||
}
|
|
||||||
if aliceBal.Balance != int64(pushAmt) {
|
|
||||||
t.Fatalf("alice's balance is incorrect: expected %v got %v",
|
|
||||||
pushAmt, aliceBal.Balance)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that we're done with the test, the channel can be closed.
|
// Now that we're done with the test, the channel can be closed.
|
||||||
ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout)
|
ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout)
|
||||||
@@ -2864,8 +2924,8 @@ func findTxAtHeight(ctx context.Context, t *harnessTest, height int32,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// testChannelBalance creates a new channel between Alice and Bob, then
|
// testChannelBalance creates a new channel between Alice and Bob, then checks
|
||||||
// checks channel balance to be equal amount specified while creation of channel.
|
// channel balance to be equal amount specified while creation of channel.
|
||||||
func testChannelBalance(net *lntest.NetworkHarness, t *harnessTest) {
|
func testChannelBalance(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
|
|
||||||
@@ -2875,20 +2935,28 @@ func testChannelBalance(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
|
|
||||||
// Creates a helper closure to be used below which asserts the proper
|
// Creates a helper closure to be used below which asserts the proper
|
||||||
// response to a channel balance RPC.
|
// response to a channel balance RPC.
|
||||||
checkChannelBalance := func(node lnrpc.LightningClient,
|
checkChannelBalance := func(node *lntest.HarnessNode,
|
||||||
amount btcutil.Amount) {
|
local, remote btcutil.Amount) {
|
||||||
|
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
expectedResponse := &lnrpc.ChannelBalanceResponse{
|
||||||
response, err := node.ChannelBalance(ctxt, &lnrpc.ChannelBalanceRequest{})
|
LocalBalance: &lnrpc.Amount{
|
||||||
if err != nil {
|
Sat: uint64(local),
|
||||||
t.Fatalf("unable to get channel balance: %v", err)
|
Msat: uint64(lnwire.NewMSatFromSatoshis(local)),
|
||||||
}
|
},
|
||||||
|
RemoteBalance: &lnrpc.Amount{
|
||||||
balance := btcutil.Amount(response.Balance)
|
Sat: uint64(remote),
|
||||||
if balance != amount {
|
Msat: uint64(lnwire.NewMSatFromSatoshis(
|
||||||
t.Fatalf("channel balance wrong: %v != %v", balance,
|
remote,
|
||||||
amount)
|
)),
|
||||||
|
},
|
||||||
|
UnsettledLocalBalance: &lnrpc.Amount{},
|
||||||
|
UnsettledRemoteBalance: &lnrpc.Amount{},
|
||||||
|
PendingOpenLocalBalance: &lnrpc.Amount{},
|
||||||
|
PendingOpenRemoteBalance: &lnrpc.Amount{},
|
||||||
|
// Deprecated fields.
|
||||||
|
Balance: int64(local),
|
||||||
}
|
}
|
||||||
|
assertChannelBalanceResp(t, node, expectedResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before beginning, make sure alice and bob are connected.
|
// Before beginning, make sure alice and bob are connected.
|
||||||
@@ -2926,10 +2994,10 @@ func testChannelBalance(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
|
|
||||||
// As this is a single funder channel, Alice's balance should be
|
// As this is a single funder channel, Alice's balance should be
|
||||||
// exactly 0.5 BTC since now state transitions have taken place yet.
|
// exactly 0.5 BTC since now state transitions have taken place yet.
|
||||||
checkChannelBalance(net.Alice, amount-cType.calcStaticFee(0))
|
checkChannelBalance(net.Alice, amount-cType.calcStaticFee(0), 0)
|
||||||
|
|
||||||
// Ensure Bob currently has no available balance within the channel.
|
// Ensure Bob currently has no available balance within the channel.
|
||||||
checkChannelBalance(net.Bob, 0)
|
checkChannelBalance(net.Bob, 0, amount-cType.calcStaticFee(0))
|
||||||
|
|
||||||
// Finally close the channel between Alice and Bob, asserting that the
|
// Finally close the channel between Alice and Bob, asserting that the
|
||||||
// channel has been properly closed on-chain.
|
// channel has been properly closed on-chain.
|
||||||
@@ -2946,6 +3014,44 @@ func testChannelUnsettledBalance(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
const chanAmt = btcutil.Amount(1000000)
|
const chanAmt = btcutil.Amount(1000000)
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
|
|
||||||
|
// Creates a helper closure to be used below which asserts the proper
|
||||||
|
// response to a channel balance RPC.
|
||||||
|
checkChannelBalance := func(node *lntest.HarnessNode,
|
||||||
|
local, remote, unsettledLocal, unsettledRemote btcutil.Amount) {
|
||||||
|
|
||||||
|
expectedResponse := &lnrpc.ChannelBalanceResponse{
|
||||||
|
LocalBalance: &lnrpc.Amount{
|
||||||
|
Sat: uint64(local),
|
||||||
|
Msat: uint64(lnwire.NewMSatFromSatoshis(
|
||||||
|
local,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
RemoteBalance: &lnrpc.Amount{
|
||||||
|
Sat: uint64(remote),
|
||||||
|
Msat: uint64(lnwire.NewMSatFromSatoshis(
|
||||||
|
remote,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
UnsettledLocalBalance: &lnrpc.Amount{
|
||||||
|
Sat: uint64(unsettledLocal),
|
||||||
|
Msat: uint64(lnwire.NewMSatFromSatoshis(
|
||||||
|
unsettledLocal,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
UnsettledRemoteBalance: &lnrpc.Amount{
|
||||||
|
Sat: uint64(unsettledRemote),
|
||||||
|
Msat: uint64(lnwire.NewMSatFromSatoshis(
|
||||||
|
unsettledRemote,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
PendingOpenLocalBalance: &lnrpc.Amount{},
|
||||||
|
PendingOpenRemoteBalance: &lnrpc.Amount{},
|
||||||
|
// Deprecated fields.
|
||||||
|
Balance: int64(local),
|
||||||
|
}
|
||||||
|
assertChannelBalanceResp(t, node, expectedResponse)
|
||||||
|
}
|
||||||
|
|
||||||
// Create carol in hodl mode.
|
// Create carol in hodl mode.
|
||||||
carol, err := net.NewNode("Carol", []string{"--hodl.exit-settle"})
|
carol, err := net.NewNode("Carol", []string{"--hodl.exit-settle"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -2984,6 +3090,17 @@ func testChannelUnsettledBalance(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
"timeout: %v", err)
|
"timeout: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cType, err := channelCommitType(net.Alice, chanPointAlice)
|
||||||
|
require.NoError(t.t, err, "unable to get channel type")
|
||||||
|
|
||||||
|
// Check alice's channel balance, which should have zero remote and zero
|
||||||
|
// pending balance.
|
||||||
|
checkChannelBalance(net.Alice, chanAmt-cType.calcStaticFee(0), 0, 0, 0)
|
||||||
|
|
||||||
|
// Check carol's channel balance, which should have zero local and zero
|
||||||
|
// pending balance.
|
||||||
|
checkChannelBalance(carol, 0, chanAmt-cType.calcStaticFee(0), 0, 0)
|
||||||
|
|
||||||
// Channel should be ready for payments.
|
// Channel should be ready for payments.
|
||||||
const (
|
const (
|
||||||
payAmt = 100
|
payAmt = 100
|
||||||
@@ -3060,6 +3177,17 @@ func testChannelUnsettledBalance(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check alice's channel balance, which should have a remote unsettled
|
||||||
|
// balance that equals to the amount of invoices * payAmt. The remote
|
||||||
|
// balance remains zero.
|
||||||
|
aliceLocal := chanAmt - cType.calcStaticFee(0) - numInvoices*payAmt
|
||||||
|
checkChannelBalance(net.Alice, aliceLocal, 0, 0, numInvoices*payAmt)
|
||||||
|
|
||||||
|
// Check carol's channel balance, which should have a local unsettled
|
||||||
|
// balance that equals to the amount of invoices * payAmt. The local
|
||||||
|
// balance remains zero.
|
||||||
|
checkChannelBalance(carol, 0, aliceLocal, numInvoices*payAmt, 0)
|
||||||
|
|
||||||
// Force and assert the channel closure.
|
// Force and assert the channel closure.
|
||||||
ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout)
|
ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout)
|
||||||
closeChannelAndAssert(ctxt, t, net, net.Alice, chanPointAlice, true)
|
closeChannelAndAssert(ctxt, t, net, net.Alice, chanPointAlice, true)
|
||||||
@@ -9160,10 +9288,10 @@ func testRevokedCloseRetributionAltruistWatchtower(net *lntest.NetworkHarness,
|
|||||||
t.Fatalf("unable to get dave's balance: %v", err)
|
t.Fatalf("unable to get dave's balance: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if daveBalResp.Balance != 0 {
|
if daveBalResp.LocalBalance.Sat != 0 {
|
||||||
predErr = fmt.Errorf("Dave should end up with zero "+
|
predErr = fmt.Errorf("Dave should end up with zero "+
|
||||||
"channel balance, instead has %d",
|
"channel balance, instead has %d",
|
||||||
daveBalResp.Balance)
|
daveBalResp.LocalBalance.Sat)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11080,10 +11208,7 @@ func testSwitchCircuitPersistence(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// the nodes in the network.
|
// the nodes in the network.
|
||||||
err = wait.Predicate(func() bool {
|
err = wait.Predicate(func() bool {
|
||||||
predErr = assertNumActiveHtlcs(nodes, 0)
|
predErr = assertNumActiveHtlcs(nodes, 0)
|
||||||
if predErr != nil {
|
return predErr == nil
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
|
|
||||||
}, time.Second*15)
|
}, time.Second*15)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+60
-9
@@ -2852,16 +2852,36 @@ func (r *rpcServer) WalletBalance(ctx context.Context,
|
|||||||
// ChannelBalance returns the total available channel flow across all open
|
// ChannelBalance returns the total available channel flow across all open
|
||||||
// channels in satoshis.
|
// channels in satoshis.
|
||||||
func (r *rpcServer) ChannelBalance(ctx context.Context,
|
func (r *rpcServer) ChannelBalance(ctx context.Context,
|
||||||
in *lnrpc.ChannelBalanceRequest) (*lnrpc.ChannelBalanceResponse, error) {
|
in *lnrpc.ChannelBalanceRequest) (
|
||||||
|
*lnrpc.ChannelBalanceResponse, error) {
|
||||||
|
|
||||||
|
var (
|
||||||
|
localBalance lnwire.MilliSatoshi
|
||||||
|
remoteBalance lnwire.MilliSatoshi
|
||||||
|
unsettledLocalBalance lnwire.MilliSatoshi
|
||||||
|
unsettledRemoteBalance lnwire.MilliSatoshi
|
||||||
|
pendingOpenLocalBalance lnwire.MilliSatoshi
|
||||||
|
pendingOpenRemoteBalance lnwire.MilliSatoshi
|
||||||
|
)
|
||||||
|
|
||||||
openChannels, err := r.server.remoteChanDB.FetchAllOpenChannels()
|
openChannels, err := r.server.remoteChanDB.FetchAllOpenChannels()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var balance btcutil.Amount
|
|
||||||
for _, channel := range openChannels {
|
for _, channel := range openChannels {
|
||||||
balance += channel.LocalCommitment.LocalBalance.ToSatoshis()
|
c := channel.LocalCommitment
|
||||||
|
localBalance += c.LocalBalance
|
||||||
|
remoteBalance += c.RemoteBalance
|
||||||
|
|
||||||
|
// Add pending htlc amount.
|
||||||
|
for _, htlc := range c.Htlcs {
|
||||||
|
if htlc.Incoming {
|
||||||
|
unsettledLocalBalance += htlc.Amt
|
||||||
|
} else {
|
||||||
|
unsettledRemoteBalance += htlc.Amt
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pendingChannels, err := r.server.remoteChanDB.FetchPendingChannels()
|
pendingChannels, err := r.server.remoteChanDB.FetchPendingChannels()
|
||||||
@@ -2869,17 +2889,48 @@ func (r *rpcServer) ChannelBalance(ctx context.Context,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var pendingOpenBalance btcutil.Amount
|
|
||||||
for _, channel := range pendingChannels {
|
for _, channel := range pendingChannels {
|
||||||
pendingOpenBalance += channel.LocalCommitment.LocalBalance.ToSatoshis()
|
c := channel.LocalCommitment
|
||||||
|
pendingOpenLocalBalance += c.LocalBalance
|
||||||
|
pendingOpenRemoteBalance += c.RemoteBalance
|
||||||
}
|
}
|
||||||
|
|
||||||
rpcsLog.Debugf("[channelbalance] balance=%v pending-open=%v",
|
rpcsLog.Debugf("[channelbalance] local_balance=%v remote_balance=%v "+
|
||||||
balance, pendingOpenBalance)
|
"unsettled_local_balance=%v unsettled_remote_balance=%v "+
|
||||||
|
"pending_open_local_balance=%v pending_open_remove_balance",
|
||||||
|
localBalance, remoteBalance, unsettledLocalBalance,
|
||||||
|
unsettledRemoteBalance, pendingOpenLocalBalance,
|
||||||
|
pendingOpenRemoteBalance)
|
||||||
|
|
||||||
return &lnrpc.ChannelBalanceResponse{
|
return &lnrpc.ChannelBalanceResponse{
|
||||||
Balance: int64(balance),
|
LocalBalance: &lnrpc.Amount{
|
||||||
PendingOpenBalance: int64(pendingOpenBalance),
|
Sat: uint64(localBalance.ToSatoshis()),
|
||||||
|
Msat: uint64(localBalance),
|
||||||
|
},
|
||||||
|
RemoteBalance: &lnrpc.Amount{
|
||||||
|
Sat: uint64(remoteBalance.ToSatoshis()),
|
||||||
|
Msat: uint64(remoteBalance),
|
||||||
|
},
|
||||||
|
UnsettledLocalBalance: &lnrpc.Amount{
|
||||||
|
Sat: uint64(unsettledLocalBalance.ToSatoshis()),
|
||||||
|
Msat: uint64(unsettledLocalBalance),
|
||||||
|
},
|
||||||
|
UnsettledRemoteBalance: &lnrpc.Amount{
|
||||||
|
Sat: uint64(unsettledRemoteBalance.ToSatoshis()),
|
||||||
|
Msat: uint64(unsettledRemoteBalance),
|
||||||
|
},
|
||||||
|
PendingOpenLocalBalance: &lnrpc.Amount{
|
||||||
|
Sat: uint64(pendingOpenLocalBalance.ToSatoshis()),
|
||||||
|
Msat: uint64(pendingOpenLocalBalance),
|
||||||
|
},
|
||||||
|
PendingOpenRemoteBalance: &lnrpc.Amount{
|
||||||
|
Sat: uint64(pendingOpenRemoteBalance.ToSatoshis()),
|
||||||
|
Msat: uint64(pendingOpenRemoteBalance),
|
||||||
|
},
|
||||||
|
|
||||||
|
// Deprecated fields.
|
||||||
|
Balance: int64(localBalance.ToSatoshis()),
|
||||||
|
PendingOpenBalance: int64(pendingOpenLocalBalance.ToSatoshis()),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user