Merge pull request #6592 from priyanshiiit/walletreserve

lnrpc+lncli: adds required wallet reserve rpc & cli
This commit is contained in:
Oliver Gugger authored and GitHub committed 2022-06-28 20:59:55 +02:00
commit 1ea8ea6c9e
21 files changed
+2642 -2112

No files matched your search

+48
View File
@@ -66,6 +66,7 @@ func walletCommands() []cli.Command {
listLeasesCommand,
psbtCommand,
accountsCommand,
requiredReserveCommand,
},
},
}
@@ -1083,6 +1084,53 @@ func listAccounts(ctx *cli.Context) error {
return nil
}
var requiredReserveCommand = cli.Command{
Name: "requiredreserve",
Usage: "Returns the wallet reserve.",
Description: `
Returns the minimum amount of satoshis that should be kept in the
wallet in order to fee bump anchor channels if necessary. The value
scales with the number of public anchor channels but is capped at
a maximum.
Use the flag --additional_channels to get the reserve value based
on the additional channels you would like to open.
`,
Flags: []cli.Flag{
cli.Uint64Flag{
Name: "additional_channels",
Usage: "(optional) specify the additional public channels " +
"that you would like to open",
},
},
Action: actionDecorator(requiredReserve),
}
func requiredReserve(ctx *cli.Context) error {
ctxc := getContext()
// Display the command's help message if we do not have the expected
// number of arguments/flags.
if ctx.NArg() > 0 || ctx.NumFlags() > 1 {
return cli.ShowCommandHelp(ctx, "requiredreserve")
}
walletClient, cleanUp := getWalletClient(ctx)
defer cleanUp()
req := &walletrpc.RequiredReserveRequest{
AdditionalPublicChannels: uint32(ctx.Uint64("additional_channels")),
}
resp, err := walletClient.RequiredReserve(ctxc, req)
if err != nil {
return err
}
printRespJSON(resp)
return nil
}
var importAccountCommand = cli.Command{
Name: "import",
Usage: "Import an on-chain account into the wallet through its " +
+5 -2
View File
@@ -14,15 +14,18 @@
* [Add previous_outpoints to listchaintxns](https://github.com/lightningnetwork/lnd/pull/6321)
## Bug Fixes
* Fixed data race found in
[`TestSerializeHTLCEntries`](https://github.com/lightningnetwork/lnd/pull/6673).
## RPC Server
* [Add wallet reserve rpc & field in wallet balance](https://github.com/lightningnetwork/lnd/pull/6592)
# Contributors (Alphabetical Order)
* Elle Mouton
* ErikEk
* Priyansh Rastogi
* Yong Yu
* Yong Yu
+1549 -1536
View File
File diff suppressed because it is too large. Load diff
+3
View File
@@ -2567,6 +2567,9 @@ message WalletBalanceResponse {
// other usage.
int64 locked_balance = 5;
// The amount of reserve required.
int64 reserved_balance_anchor_chan = 6;
// A mapping of each wallet account's name to its balance.
map<string, WalletAccountBalance> account_balance = 4;
}
+5
View File
@@ -6646,6 +6646,11 @@
"format": "int64",
"description": "The total amount of wallet UTXOs held in outputs that are locked for\nother usage."
},
"reserved_balance_anchor_chan": {
"type": "string",
"format": "int64",
"description": "The amount of reserve required."
},
"account_balance": {
"type": "object",
"additionalProperties": {
+4
View File
@@ -67,4 +67,8 @@ type Config struct {
// ChainParams are the parameters of the wallet's backing chain.
ChainParams *chaincfg.Params
// CurrentNumAnchorChans returns the current number of non-private
// anchor channels the wallet should be ready to fee bump if needed.
CurrentNumAnchorChans func() (int, error)
}
File diff suppressed because it is too large. Load diff
+83
View File
@@ -290,6 +290,42 @@ func local_request_WalletKit_ListAccounts_0(ctx context.Context, marshaler runti
}
var (
filter_WalletKit_RequiredReserve_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_WalletKit_RequiredReserve_0(ctx context.Context, marshaler runtime.Marshaler, client WalletKitClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq RequiredReserveRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WalletKit_RequiredReserve_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.RequiredReserve(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WalletKit_RequiredReserve_0(ctx context.Context, marshaler runtime.Marshaler, server WalletKitServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq RequiredReserveRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WalletKit_RequiredReserve_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.RequiredReserve(ctx, &protoReq)
return msg, metadata, err
}
func request_WalletKit_ImportAccount_0(ctx context.Context, marshaler runtime.Marshaler, client WalletKitClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ImportAccountRequest
var metadata runtime.ServerMetadata
@@ -892,6 +928,29 @@ func RegisterWalletKitHandlerServer(ctx context.Context, mux *runtime.ServeMux,
})
mux.Handle("GET", pattern_WalletKit_RequiredReserve_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/walletrpc.WalletKit/RequiredReserve", runtime.WithHTTPPathPattern("/v2/wallet/reserve"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WalletKit_RequiredReserve_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WalletKit_RequiredReserve_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_WalletKit_ImportAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -1369,6 +1428,26 @@ func RegisterWalletKitHandlerClient(ctx context.Context, mux *runtime.ServeMux,
})
mux.Handle("GET", pattern_WalletKit_RequiredReserve_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/walletrpc.WalletKit/RequiredReserve", runtime.WithHTTPPathPattern("/v2/wallet/reserve"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WalletKit_RequiredReserve_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WalletKit_RequiredReserve_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_WalletKit_ImportAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -1629,6 +1708,8 @@ var (
pattern_WalletKit_ListAccounts_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v2", "wallet", "accounts"}, ""))
pattern_WalletKit_RequiredReserve_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v2", "wallet", "reserve"}, ""))
pattern_WalletKit_ImportAccount_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v2", "wallet", "accounts", "import"}, ""))
pattern_WalletKit_ImportPublicKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v2", "wallet", "key", "import"}, ""))
@@ -1671,6 +1752,8 @@ var (
forward_WalletKit_ListAccounts_0 = runtime.ForwardResponseMessage
forward_WalletKit_RequiredReserve_0 = runtime.ForwardResponseMessage
forward_WalletKit_ImportAccount_0 = runtime.ForwardResponseMessage
forward_WalletKit_ImportPublicKey_0 = runtime.ForwardResponseMessage
+25
View File
@@ -224,6 +224,31 @@ func RegisterWalletKitJSONCallbacks(registry map[string]func(ctx context.Context
callback(string(respBytes), nil)
}
registry["walletrpc.WalletKit.RequiredReserve"] = func(ctx context.Context,
conn *grpc.ClientConn, reqJSON string, callback func(string, error)) {
req := &RequiredReserveRequest{}
err := marshaler.Unmarshal([]byte(reqJSON), req)
if err != nil {
callback("", err)
return
}
client := NewWalletKitClient(conn)
resp, err := client.RequiredReserve(ctx, req)
if err != nil {
callback("", err)
return
}
respBytes, err := marshaler.Marshal(resp)
if err != nil {
callback("", err)
return
}
callback(string(respBytes), nil)
}
registry["walletrpc.WalletKit.ImportAccount"] = func(ctx context.Context,
conn *grpc.ClientConn, reqJSON string, callback func(string, error)) {
+18
View File
@@ -64,6 +64,14 @@ service WalletKit {
*/
rpc ListAccounts (ListAccountsRequest) returns (ListAccountsResponse);
/*
RequiredReserve returns the minimum amount of satoshis that should be kept
in the wallet in order to fee bump anchor channels if necessary. The value
scales with the number of public anchor channels but is capped at a maximum.
*/
rpc RequiredReserve (RequiredReserveRequest)
returns (RequiredReserveResponse);
/*
ImportAccount imports an account backed by an account extended public key.
The master key fingerprint denotes the fingerprint of the root key
@@ -400,6 +408,16 @@ message ListAccountsResponse {
repeated Account accounts = 1;
}
message RequiredReserveRequest {
// The number of additional channels the user would like to open.
uint32 additional_public_channels = 1;
}
message RequiredReserveResponse {
// The amount of reserve required.
int64 required_reserve = 1;
}
message ImportAccountRequest {
// A name to identify the account with.
string name = 1;
+43
View File
@@ -399,6 +399,39 @@
]
}
},
"/v2/wallet/reserve": {
"get": {
"summary": "RequiredReserve returns the minimum amount of satoshis that should be kept\nin the wallet in order to fee bump anchor channels if necessary. The value\nscales with the number of public anchor channels but is capped at a maximum.",
"operationId": "WalletKit_RequiredReserve",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/walletrpcRequiredReserveResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "additional_public_channels",
"description": "The number of additional channels the user would like to open.",
"in": "query",
"required": false,
"type": "integer",
"format": "int64"
}
],
"tags": [
"WalletKit"
]
}
},
"/v2/wallet/send": {
"post": {
"summary": "SendOutputs is similar to the existing sendmany call in Bitcoind, and\nallows the caller to create a transaction that sends to several outputs at\nonce. This is ideal when wanting to batch create a set of transactions.",
@@ -1467,6 +1500,16 @@
"walletrpcReleaseOutputResponse": {
"type": "object"
},
"walletrpcRequiredReserveResponse": {
"type": "object",
"properties": {
"required_reserve": {
"type": "string",
"format": "int64",
"description": "The amount of reserve required."
}
}
},
"walletrpcSendOutputsRequest": {
"type": "object",
"properties": {
+2
View File
@@ -55,6 +55,8 @@ http:
body: "*"
- selector: walletrpc.WalletKit.ListAccounts
get: "/v2/wallet/accounts"
- selector: walletrpc.WalletKit.RequiredReserve
get: "/v2/wallet/reserve"
- selector: walletrpc.WalletKit.ImportAccount
post: "/v2/wallet/accounts/import"
body: "*"
+44
View File
@@ -58,6 +58,11 @@ type WalletKitClient interface {
//wallet accounts and return only those matching.
ListAccounts(ctx context.Context, in *ListAccountsRequest, opts ...grpc.CallOption) (*ListAccountsResponse, error)
//
//RequiredReserve returns the minimum amount of satoshis that should be kept
//in the wallet in order to fee bump anchor channels if necessary. The value
//scales with the number of public anchor channels but is capped at a maximum.
RequiredReserve(ctx context.Context, in *RequiredReserveRequest, opts ...grpc.CallOption) (*RequiredReserveResponse, error)
//
//ImportAccount imports an account backed by an account extended public key.
//The master key fingerprint denotes the fingerprint of the root key
//corresponding to the account public key (also known as the key with
@@ -281,6 +286,15 @@ func (c *walletKitClient) ListAccounts(ctx context.Context, in *ListAccountsRequ
return out, nil
}
func (c *walletKitClient) RequiredReserve(ctx context.Context, in *RequiredReserveRequest, opts ...grpc.CallOption) (*RequiredReserveResponse, error) {
out := new(RequiredReserveResponse)
err := c.cc.Invoke(ctx, "/walletrpc.WalletKit/RequiredReserve", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *walletKitClient) ImportAccount(ctx context.Context, in *ImportAccountRequest, opts ...grpc.CallOption) (*ImportAccountResponse, error) {
out := new(ImportAccountResponse)
err := c.cc.Invoke(ctx, "/walletrpc.WalletKit/ImportAccount", in, out, opts...)
@@ -432,6 +446,11 @@ type WalletKitServer interface {
//wallet accounts and return only those matching.
ListAccounts(context.Context, *ListAccountsRequest) (*ListAccountsResponse, error)
//
//RequiredReserve returns the minimum amount of satoshis that should be kept
//in the wallet in order to fee bump anchor channels if necessary. The value
//scales with the number of public anchor channels but is capped at a maximum.
RequiredReserve(context.Context, *RequiredReserveRequest) (*RequiredReserveResponse, error)
//
//ImportAccount imports an account backed by an account extended public key.
//The master key fingerprint denotes the fingerprint of the root key
//corresponding to the account public key (also known as the key with
@@ -604,6 +623,9 @@ func (UnimplementedWalletKitServer) NextAddr(context.Context, *AddrRequest) (*Ad
func (UnimplementedWalletKitServer) ListAccounts(context.Context, *ListAccountsRequest) (*ListAccountsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListAccounts not implemented")
}
func (UnimplementedWalletKitServer) RequiredReserve(context.Context, *RequiredReserveRequest) (*RequiredReserveResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method RequiredReserve not implemented")
}
func (UnimplementedWalletKitServer) ImportAccount(context.Context, *ImportAccountRequest) (*ImportAccountResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ImportAccount not implemented")
}
@@ -797,6 +819,24 @@ func _WalletKit_ListAccounts_Handler(srv interface{}, ctx context.Context, dec f
return interceptor(ctx, in, info, handler)
}
func _WalletKit_RequiredReserve_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RequiredReserveRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WalletKitServer).RequiredReserve(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/walletrpc.WalletKit/RequiredReserve",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WalletKitServer).RequiredReserve(ctx, req.(*RequiredReserveRequest))
}
return interceptor(ctx, in, info, handler)
}
func _WalletKit_ImportAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ImportAccountRequest)
if err := dec(in); err != nil {
@@ -1052,6 +1092,10 @@ var WalletKit_ServiceDesc = grpc.ServiceDesc{
MethodName: "ListAccounts",
Handler: _WalletKit_ListAccounts_Handler,
},
{
MethodName: "RequiredReserve",
Handler: _WalletKit_RequiredReserve_Handler,
},
{
MethodName: "ImportAccount",
Handler: _WalletKit_ImportAccount_Handler,
+25
View File
@@ -136,6 +136,10 @@ var (
Entity: "onchain",
Action: "read",
}},
"/walletrpc.WalletKit/RequiredReserve": {{
Entity: "onchain",
Action: "read",
}},
"/walletrpc.WalletKit/ImportAccount": {{
Entity: "onchain",
Action: "write",
@@ -1468,6 +1472,27 @@ func (w *WalletKit) ListAccounts(ctx context.Context,
return &ListAccountsResponse{Accounts: rpcAccounts}, nil
}
// RequiredReserve returns the minimum amount of satoshis that should be
// kept in the wallet in order to fee bump anchor channels if necessary.
// The value scales with the number of public anchor channels but is
// capped at a maximum.
func (w *WalletKit) RequiredReserve(ctx context.Context,
req *RequiredReserveRequest) (*RequiredReserveResponse, error) {
numAnchorChans, err := w.cfg.CurrentNumAnchorChans()
if err != nil {
return nil, err
}
additionalChans := req.AdditionalPublicChannels
totalChans := uint32(numAnchorChans) + additionalChans
reserved := w.cfg.Wallet.RequiredReserve(totalChans)
return &RequiredReserveResponse{
RequiredReserve: int64(reserved),
}, nil
}
// parseAddrType parses an address type from its RPC representation to a
// *waddrmgr.AddressType.
func parseAddrType(addrType AddressType,
+33
View File
@@ -341,6 +341,39 @@ func testAnchorReservedValue(net *lntest.NetworkHarness, t *harnessTest) {
// The reserved value is now back in Alice's wallet.
aliceBalance := waitForConfirmedBalance()
// The reserved value should be equal to the required reserve for anchor
// channels.
walletBalanceResp, err := alice.WalletBalance(
ctxb, &lnrpc.WalletBalanceRequest{},
)
require.NoError(t.t, err)
require.Equal(
t.t, aliceBalance, walletBalanceResp.ReservedBalanceAnchorChan,
)
additionalChannels := int64(1)
// Required reserve when additional channels are provided.
requiredReserveResp, err := alice.WalletKitClient.RequiredReserve(
ctxb, &walletrpc.RequiredReserveRequest{
AdditionalPublicChannels: uint32(additionalChannels),
},
)
require.NoError(t.t, err)
additionalReservedValue := btcutil.Amount(additionalChannels *
int64(lnwallet.AnchorChanReservedValue))
totalReserved := btcutil.Amount(aliceBalance) + additionalReservedValue
// The total reserved value should not exceed the maximum value reserved
// for anchor channels.
if totalReserved > lnwallet.MaxAnchorChanReservedValue {
totalReserved = lnwallet.MaxAnchorChanReservedValue
}
require.Equal(
t.t, int64(totalReserved), requiredReserveResp.RequiredReserve,
)
// Alice closes channel, should now be allowed to send everything to an
// external address.
for _, chanPoint := range chanPoints {
+5
View File
@@ -105,6 +105,11 @@ func (w *WalletController) ListAccounts(string,
return nil, nil
}
// RequiredReserve currently returns a dummy value.
func (w *WalletController) RequiredReserve(uint32) btcutil.Amount {
return 0
}
// ImportAccount currently returns a dummy value.
func (w *WalletController) ImportAccount(string, *hdkeychain.ExtendedKey,
uint32, *waddrmgr.AddressType, bool) (*waddrmgr.AccountProperties,
+16
View File
@@ -711,6 +711,22 @@ func (b *BtcWallet) ListAccounts(name string,
return res, nil
}
// RequiredReserve returns the minimum amount of satoshis that should be
// kept in the wallet in order to fee bump anchor channels if necessary.
// The value scales with the number of public anchor channels but is
// capped at a maximum.
func (b *BtcWallet) RequiredReserve(
numAnchorChans uint32) btcutil.Amount {
anchorChanReservedValue := lnwallet.AnchorChanReservedValue
reserved := btcutil.Amount(numAnchorChans) * anchorChanReservedValue
if reserved > lnwallet.MaxAnchorChanReservedValue {
reserved = lnwallet.MaxAnchorChanReservedValue
}
return reserved
}
// ImportAccount imports an account backed by an account extended public key.
// The master key fingerprint denotes the fingerprint of the root key
// corresponding to the account public key (also known as the key with
+6
View File
@@ -244,6 +244,12 @@ type WalletController interface {
ListAccounts(string, *waddrmgr.KeyScope) ([]*waddrmgr.AccountProperties,
error)
// RequiredReserve returns the minimum amount of satoshis that should be
// kept in the wallet in order to fee bump anchor channels if necessary.
// The value scales with the number of public anchor channels but is
// capped at a maximum.
RequiredReserve(uint32) btcutil.Amount
// ImportAccount imports an account backed by an account extended public
// key. The master key fingerprint denotes the fingerprint of the root
// key corresponding to the account public key (also known as the key
+11 -11
View File
@@ -35,18 +35,18 @@ const (
// outside word.
msgBufferSize = 100
// anchorChanReservedValue is the amount we'll keep around in the
// AnchorChanReservedValue is the amount we'll keep around in the
// wallet in case we have to fee bump anchor channels on force close.
// TODO(halseth): update constant to target a specific commit size at
// set fee rate.
anchorChanReservedValue = btcutil.Amount(10_000)
AnchorChanReservedValue = btcutil.Amount(10_000)
// maxAnchorChanReservedValue is the maximum value we'll reserve for
// MaxAnchorChanReservedValue is the maximum value we'll reserve for
// anchor channel fee bumping. We cap it at 10 times the per-channel
// amount such that nodes with a high number of channels don't have to
// keep around a very large amount for the unlikely scenario that they
// all close at the same time.
maxAnchorChanReservedValue = 10 * anchorChanReservedValue
MaxAnchorChanReservedValue = 10 * AnchorChanReservedValue
)
var (
@@ -900,7 +900,7 @@ func (l *LightningWallet) enforceNewReservedValue(fundingIntent chanfunding.Inte
return nil
}
numAnchors, err := l.currentNumAnchorChans()
numAnchors, err := l.CurrentNumAnchorChans()
if err != nil {
return err
}
@@ -919,9 +919,9 @@ func (l *LightningWallet) enforceNewReservedValue(fundingIntent chanfunding.Inte
})
}
// currentNumAnchorChans returns the current number of non-private anchor
// CurrentNumAnchorChans returns the current number of non-private anchor
// channels the wallet should be ready to fee bump if needed.
func (l *LightningWallet) currentNumAnchorChans() (int, error) {
func (l *LightningWallet) CurrentNumAnchorChans() (int, error) {
// Count all anchor channels that are open or pending
// open, or waiting close.
chans, err := l.Cfg.Database.FetchAllChannels()
@@ -1046,9 +1046,9 @@ func (l *LightningWallet) CheckReservedValue(in []wire.OutPoint,
}
// We reserve a given amount for each anchor channel.
reserved := btcutil.Amount(numAnchorChans) * anchorChanReservedValue
if reserved > maxAnchorChanReservedValue {
reserved = maxAnchorChanReservedValue
reserved := btcutil.Amount(numAnchorChans) * AnchorChanReservedValue
if reserved > MaxAnchorChanReservedValue {
reserved = MaxAnchorChanReservedValue
}
if walletBalance < reserved {
@@ -1069,7 +1069,7 @@ func (l *LightningWallet) CheckReservedValue(in []wire.OutPoint,
func (l *LightningWallet) CheckReservedValueTx(req CheckReservedValueTxReq) (
btcutil.Amount, error) {
numAnchors, err := l.currentNumAnchorChans()
numAnchors, err := l.CurrentNumAnchorChans()
if err != nil {
return 0, err
}
+17 -5
View File
@@ -3136,16 +3136,28 @@ func (r *rpcServer) WalletBalance(ctx context.Context,
lockedBalance += utxoInfo.Value
}
// Get the current number of non-private anchor channels.
currentNumAnchorChans, err := r.server.cc.Wallet.CurrentNumAnchorChans()
if err != nil {
return nil, err
}
// Get the required reserve for the wallet.
requiredReserve := r.server.cc.Wallet.RequiredReserve(
uint32(currentNumAnchorChans),
)
rpcsLog.Debugf("[walletbalance] Total balance=%v (confirmed=%v, "+
"unconfirmed=%v)", totalBalance, confirmedBalance,
unconfirmedBalance)
return &lnrpc.WalletBalanceResponse{
TotalBalance: int64(totalBalance),
ConfirmedBalance: int64(confirmedBalance),
UnconfirmedBalance: int64(unconfirmedBalance),
LockedBalance: int64(lockedBalance),
AccountBalance: rpcAccountBalances,
TotalBalance: int64(totalBalance),
ConfirmedBalance: int64(confirmedBalance),
UnconfirmedBalance: int64(unconfirmedBalance),
LockedBalance: int64(lockedBalance),
ReservedBalanceAnchorChan: int64(requiredReserve),
AccountBalance: rpcAccountBalances,
}, nil
}
+3
View File
@@ -193,6 +193,9 @@ func (s *subRPCServerConfigs) PopulateDependencies(cfg *Config,
subCfgValue.FieldByName("ChainParams").Set(
reflect.ValueOf(activeNetParams),
)
subCfgValue.FieldByName("CurrentNumAnchorChans").Set(
reflect.ValueOf(cc.Wallet.CurrentNumAnchorChans),
)
case *autopilotrpc.Config:
subCfgValue := extractReflectValue(subCfg)