mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-04-09 20:49:08 +02:00
Merge pull request #4095 from carlaKC/4036-surfacepushamounts
lnrpc: Add push amount to listchannels
This commit is contained in:
commit
c3ffdb7af4
@ -144,6 +144,15 @@ var (
|
||||
// ErrChanBorked is returned when a caller attempts to mutate a borked
|
||||
// channel.
|
||||
ErrChanBorked = fmt.Errorf("cannot mutate borked channel")
|
||||
|
||||
// errLogEntryNotFound is returned when we cannot find a log entry at
|
||||
// the height requested in the revocation log.
|
||||
errLogEntryNotFound = fmt.Errorf("log entry not found")
|
||||
|
||||
// errHeightNotFound is returned when a query for channel balances at
|
||||
// a height that we have not reached yet is made.
|
||||
errHeightNotReached = fmt.Errorf("height requested greater than " +
|
||||
"current commit height")
|
||||
)
|
||||
|
||||
// ChannelType is an enum-like type that describes one of several possible
|
||||
@ -1391,6 +1400,44 @@ func (c *OpenChannel) UpdateCommitment(newCommitment *ChannelCommitment,
|
||||
return nil
|
||||
}
|
||||
|
||||
// BalancesAtHeight returns the local and remote balances on our commitment
|
||||
// transactions as of a given height.
|
||||
//
|
||||
// NOTE: these are our balances *after* subtracting the commitment fee and
|
||||
// anchor outputs.
|
||||
func (c *OpenChannel) BalancesAtHeight(height uint64) (lnwire.MilliSatoshi,
|
||||
lnwire.MilliSatoshi, error) {
|
||||
|
||||
if height > c.LocalCommitment.CommitHeight &&
|
||||
height > c.RemoteCommitment.CommitHeight {
|
||||
|
||||
return 0, 0, errHeightNotReached
|
||||
}
|
||||
|
||||
// If our current commit is as the desired height, we can return our
|
||||
// current balances.
|
||||
if c.LocalCommitment.CommitHeight == height {
|
||||
return c.LocalCommitment.LocalBalance,
|
||||
c.LocalCommitment.RemoteBalance, nil
|
||||
}
|
||||
|
||||
// If our current remote commit is at the desired height, we can return
|
||||
// the current balances.
|
||||
if c.RemoteCommitment.CommitHeight == height {
|
||||
return c.RemoteCommitment.LocalBalance,
|
||||
c.RemoteCommitment.RemoteBalance, nil
|
||||
}
|
||||
|
||||
// If we are not currently on the height requested, we need to look up
|
||||
// the previous height to obtain our balances at the given height.
|
||||
commit, err := c.FindPreviousState(height)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
return commit.LocalBalance, commit.RemoteBalance, nil
|
||||
}
|
||||
|
||||
// HTLC is the on-disk representation of a hash time-locked contract. HTLCs are
|
||||
// contained within ChannelDeltas which encode the current state of the
|
||||
// commitment between state updates.
|
||||
@ -3160,7 +3207,7 @@ func fetchChannelLogEntry(log kvdb.ReadBucket,
|
||||
logEntrykey := makeLogKey(updateNum)
|
||||
commitBytes := log.Get(logEntrykey[:])
|
||||
if commitBytes == nil {
|
||||
return ChannelCommitment{}, fmt.Errorf("log entry not found")
|
||||
return ChannelCommitment{}, errLogEntryNotFound
|
||||
}
|
||||
|
||||
commitReader := bytes.NewReader(commitBytes)
|
||||
|
@ -10,6 +10,8 @@ import (
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
@ -131,6 +133,25 @@ type testChannelParams struct {
|
||||
// default channel that is creates for testing.
|
||||
type testChannelOption func(params *testChannelParams)
|
||||
|
||||
// channelCommitmentOption is an option which allows overwriting of the default
|
||||
// commitment height and balances. The local boolean can be used to set these
|
||||
// balances on the local or remote commit.
|
||||
func channelCommitmentOption(height uint64, localBalance,
|
||||
remoteBalance lnwire.MilliSatoshi, local bool) testChannelOption {
|
||||
|
||||
return func(params *testChannelParams) {
|
||||
if local {
|
||||
params.channel.LocalCommitment.CommitHeight = height
|
||||
params.channel.LocalCommitment.LocalBalance = localBalance
|
||||
params.channel.LocalCommitment.RemoteBalance = remoteBalance
|
||||
} else {
|
||||
params.channel.RemoteCommitment.CommitHeight = height
|
||||
params.channel.RemoteCommitment.LocalBalance = localBalance
|
||||
params.channel.RemoteCommitment.RemoteBalance = remoteBalance
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pendingHeightOption is an option which can be used to set the height the
|
||||
// channel is marked as pending at.
|
||||
func pendingHeightOption(height uint32) testChannelOption {
|
||||
@ -1393,3 +1414,169 @@ func TestCloseChannelStatus(t *testing.T) {
|
||||
t.Fatalf("channel should have status")
|
||||
}
|
||||
}
|
||||
|
||||
// TestBalanceAtHeight tests lookup of our local and remote balance at a given
|
||||
// height.
|
||||
func TestBalanceAtHeight(t *testing.T) {
|
||||
const (
|
||||
// Values that will be set on our current local commit in
|
||||
// memory.
|
||||
localHeight = 2
|
||||
localLocalBalance = 1000
|
||||
localRemoteBalance = 1500
|
||||
|
||||
// Values that will be set on our current remote commit in
|
||||
// memory.
|
||||
remoteHeight = 3
|
||||
remoteLocalBalance = 2000
|
||||
remoteRemoteBalance = 2500
|
||||
|
||||
// Values that will be written to disk in the revocation log.
|
||||
oldHeight = 0
|
||||
oldLocalBalance = 200
|
||||
oldRemoteBalance = 300
|
||||
|
||||
// Heights to test error cases.
|
||||
unknownHeight = 1
|
||||
unreachedHeight = 4
|
||||
)
|
||||
|
||||
// putRevokedState is a helper function used to put commitments is
|
||||
// the revocation log bucket to test lookup of balances at heights that
|
||||
// are not our current height.
|
||||
putRevokedState := func(c *OpenChannel, height uint64, local,
|
||||
remote lnwire.MilliSatoshi) error {
|
||||
|
||||
err := kvdb.Update(c.Db, func(tx kvdb.RwTx) error {
|
||||
chanBucket, err := fetchChanBucketRw(
|
||||
tx, c.IdentityPub, &c.FundingOutpoint,
|
||||
c.ChainHash,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logKey := revocationLogBucket
|
||||
logBucket, err := chanBucket.CreateBucketIfNotExists(
|
||||
logKey,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make a copy of our current commitment so we do not
|
||||
// need to re-fill all the required fields and copy in
|
||||
// our new desired values.
|
||||
commit := c.LocalCommitment
|
||||
commit.CommitHeight = height
|
||||
commit.LocalBalance = local
|
||||
commit.RemoteBalance = remote
|
||||
|
||||
return appendChannelLogEntry(logBucket, &commit)
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
targetHeight uint64
|
||||
expectedLocalBalance lnwire.MilliSatoshi
|
||||
expectedRemoteBalance lnwire.MilliSatoshi
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "target is current local height",
|
||||
targetHeight: localHeight,
|
||||
expectedLocalBalance: localLocalBalance,
|
||||
expectedRemoteBalance: localRemoteBalance,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "target is current remote height",
|
||||
targetHeight: remoteHeight,
|
||||
expectedLocalBalance: remoteLocalBalance,
|
||||
expectedRemoteBalance: remoteRemoteBalance,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "need to lookup commit",
|
||||
targetHeight: oldHeight,
|
||||
expectedLocalBalance: oldLocalBalance,
|
||||
expectedRemoteBalance: oldRemoteBalance,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "height not found",
|
||||
targetHeight: unknownHeight,
|
||||
expectedLocalBalance: 0,
|
||||
expectedRemoteBalance: 0,
|
||||
expectedError: errLogEntryNotFound,
|
||||
},
|
||||
{
|
||||
name: "height not reached",
|
||||
targetHeight: unreachedHeight,
|
||||
expectedLocalBalance: 0,
|
||||
expectedRemoteBalance: 0,
|
||||
expectedError: errHeightNotReached,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cdb, cleanUp, err := makeTestDB()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to make test database: %v",
|
||||
err)
|
||||
}
|
||||
defer cleanUp()
|
||||
|
||||
// Create options to set the heights and balances of
|
||||
// our local and remote commitments.
|
||||
localCommitOpt := channelCommitmentOption(
|
||||
localHeight, localLocalBalance,
|
||||
localRemoteBalance, true,
|
||||
)
|
||||
|
||||
remoteCommitOpt := channelCommitmentOption(
|
||||
remoteHeight, remoteLocalBalance,
|
||||
remoteRemoteBalance, false,
|
||||
)
|
||||
|
||||
// Create an open channel.
|
||||
channel := createTestChannel(
|
||||
t, cdb, openChannelOption(),
|
||||
localCommitOpt, remoteCommitOpt,
|
||||
)
|
||||
|
||||
// Write an older commit to disk.
|
||||
err = putRevokedState(channel, oldHeight,
|
||||
oldLocalBalance, oldRemoteBalance)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
local, remote, err := channel.BalancesAtHeight(
|
||||
test.targetHeight,
|
||||
)
|
||||
if err != test.expectedError {
|
||||
t.Fatalf("expected: %v, got: %v",
|
||||
test.expectedError, err)
|
||||
}
|
||||
|
||||
if local != test.expectedLocalBalance {
|
||||
t.Fatalf("expected local: %v, got: %v",
|
||||
test.expectedLocalBalance, local)
|
||||
}
|
||||
|
||||
if remote != test.expectedRemoteBalance {
|
||||
t.Fatalf("expected remote: %v, got: %v",
|
||||
test.expectedRemoteBalance, remote)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
1
go.mod
1
go.mod
@ -14,6 +14,7 @@ require (
|
||||
github.com/btcsuite/btcwallet/walletdb v1.2.0
|
||||
github.com/btcsuite/btcwallet/wtxmgr v1.0.0
|
||||
github.com/btcsuite/fastsha256 v0.0.0-20160815193821-637e65642941
|
||||
github.com/coreos/bbolt v1.3.3
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/go-errors/errors v1.0.1
|
||||
github.com/golang/protobuf v1.3.1
|
||||
|
1179
lnrpc/rpc.pb.go
1179
lnrpc/rpc.pb.go
File diff suppressed because it is too large
Load Diff
@ -1428,6 +1428,15 @@ message Channel {
|
||||
cooperatively closing with the delivery_address field set.
|
||||
*/
|
||||
string close_address = 25;
|
||||
|
||||
/*
|
||||
The amount that the initiator of the channel optionally pushed to the remote
|
||||
party on channel open. This amount will be zero if the channel initiator did
|
||||
not push any funds to the remote peer. If the initiator field is true, we
|
||||
pushed this amount to our peer, if it is false, the remote peer pushed this
|
||||
amount to us.
|
||||
*/
|
||||
uint64 push_amount_sat = 27;
|
||||
}
|
||||
|
||||
message ListChannelsRequest {
|
||||
|
@ -1997,6 +1997,11 @@
|
||||
"close_address": {
|
||||
"type": "string",
|
||||
"description": "*\nClose address is the address that we will enforce payout to on cooperative\nclose if the channel was opened utilizing option upfront shutdown. This\nvalue can be set on channel open by setting close_address in an open channel\nrequest. If this value is not set, you can still choose a payout address by\ncooperatively closing with the delivery_address field set."
|
||||
},
|
||||
"push_amount_sat": {
|
||||
"type": "string",
|
||||
"format": "uint64",
|
||||
"description": "The amount that the initiator of the channel optionally pushed to the remote\nparty on channel open. This amount will be zero if the channel initiator did\nnot push any funds to the remote peer. If the initiator field is true, we\npushed this amount to our peer, if it is false, the remote peer pushed this\namount to us."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
17
rpcserver.go
17
rpcserver.go
@ -3195,6 +3195,23 @@ func createRPCOpenChannel(r *rpcServer, graph *channeldb.ChannelGraph,
|
||||
channel.UnsettledBalance += channel.PendingHtlcs[i].Amount
|
||||
}
|
||||
|
||||
// Lookup our balances at height 0, because they will reflect any
|
||||
// push amounts that may have been present when this channel was
|
||||
// created.
|
||||
localBalance, remoteBalance, err := dbChannel.BalancesAtHeight(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If we initiated opening the channel, the zero height remote balance
|
||||
// is the push amount. Otherwise, our starting balance is the push
|
||||
// amount. If there is no push amount, these values will simply be zero.
|
||||
if dbChannel.IsInitiator {
|
||||
channel.PushAmountSat = uint64(remoteBalance.ToSatoshis())
|
||||
} else {
|
||||
channel.PushAmountSat = uint64(localBalance.ToSatoshis())
|
||||
}
|
||||
|
||||
outpoint := dbChannel.FundingOutpoint
|
||||
|
||||
// Get the lifespan observed by the channel event store. If the channel is
|
||||
|
Loading…
x
Reference in New Issue
Block a user