lnrpc: adds list addresses rpc

This commit is contained in:
priyanshiiit 2022-07-23 11:06:23 +05:30
parent 99e4728eb7
commit dba77edf2a
8 changed files with 1098 additions and 348 deletions

File diff suppressed because it is too large Load Diff

View File

@ -326,6 +326,42 @@ func local_request_WalletKit_RequiredReserve_0(ctx context.Context, marshaler ru
}
var (
filter_WalletKit_ListAddresses_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_WalletKit_ListAddresses_0(ctx context.Context, marshaler runtime.Marshaler, client WalletKitClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListAddressesRequest
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_ListAddresses_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ListAddresses(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WalletKit_ListAddresses_0(ctx context.Context, marshaler runtime.Marshaler, server WalletKitServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListAddressesRequest
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_ListAddresses_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ListAddresses(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
@ -951,6 +987,29 @@ func RegisterWalletKitHandlerServer(ctx context.Context, mux *runtime.ServeMux,
})
mux.Handle("GET", pattern_WalletKit_ListAddresses_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/ListAddresses", runtime.WithHTTPPathPattern("/v2/wallet/addresses"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WalletKit_ListAddresses_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_ListAddresses_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()
@ -1448,6 +1507,26 @@ func RegisterWalletKitHandlerClient(ctx context.Context, mux *runtime.ServeMux,
})
mux.Handle("GET", pattern_WalletKit_ListAddresses_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/ListAddresses", runtime.WithHTTPPathPattern("/v2/wallet/addresses"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WalletKit_ListAddresses_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_ListAddresses_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()
@ -1710,6 +1789,8 @@ var (
pattern_WalletKit_RequiredReserve_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v2", "wallet", "reserve"}, ""))
pattern_WalletKit_ListAddresses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v2", "wallet", "addresses"}, ""))
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"}, ""))
@ -1754,6 +1835,8 @@ var (
forward_WalletKit_RequiredReserve_0 = runtime.ForwardResponseMessage
forward_WalletKit_ListAddresses_0 = runtime.ForwardResponseMessage
forward_WalletKit_ImportAccount_0 = runtime.ForwardResponseMessage
forward_WalletKit_ImportPublicKey_0 = runtime.ForwardResponseMessage

View File

@ -249,6 +249,31 @@ func RegisterWalletKitJSONCallbacks(registry map[string]func(ctx context.Context
callback(string(respBytes), nil)
}
registry["walletrpc.WalletKit.ListAddresses"] = func(ctx context.Context,
conn *grpc.ClientConn, reqJSON string, callback func(string, error)) {
req := &ListAddressesRequest{}
err := marshaler.Unmarshal([]byte(reqJSON), req)
if err != nil {
callback("", err)
return
}
client := NewWalletKitClient(conn)
resp, err := client.ListAddresses(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)) {

View File

@ -72,6 +72,13 @@ service WalletKit {
rpc RequiredReserve (RequiredReserveRequest)
returns (RequiredReserveResponse);
/*
ListAddresses retrieves all the addresses along with their balance. An
account name filter can be provided to filter through all of the
wallet accounts and return the addresses of only those matching.
*/
rpc ListAddresses (ListAddressesRequest) returns (ListAddressesResponse);
/*
ImportAccount imports an account backed by an account extended public key.
The master key fingerprint denotes the fingerprint of the root key
@ -348,14 +355,7 @@ message Account {
// The name used to identify the account.
string name = 1;
/*
The type of addresses the account supports.
AddressType | External Branch | Internal Branch
---------------------------------------------------------------------
WITNESS_PUBKEY_HASH | P2WPKH | P2WPKH
NESTED_WITNESS_PUBKEY_HASH | NP2WPKH | NP2WPKH
HYBRID_NESTED_WITNESS_PUBKEY_HASH | NP2WPKH | P2WPKH
*/
// The type of addresses the account supports.
AddressType address_type = 2;
/*
@ -397,6 +397,50 @@ message Account {
// Whether the wallet stores private keys for the account.
bool watch_only = 8;
}
message AddressProperty {
/*
The address encoded using the appropriate format depending on the
address type (base58, bech32, bech32m).
Note that lnd's internal/custom keys for channels and other
functionality are derived from the same scope. Since they
aren't really used as addresses and will never have an
on-chain balance, we'll show the public key instead (only if
the show_custom_accounts flag is provided).
*/
string address = 1;
// Denotes if the address is a change address.
bool is_internal = 2;
// The balance of the address.
int64 balance = 3;
}
message AccountWithAddresses {
// The name used to identify the account.
string name = 1;
// The type of addresses the account supports.
AddressType address_type = 2;
/*
The derivation path corresponding to the account public key. This will
always be empty for the default imported account in which single public keys
are imported into.
*/
string derivation_path = 3;
/*
List of address, its type internal/external & balance.
Note that the order of addresses will be random and not according to the
derivation index, since that information is not stored by the underlying
wallet.
*/
repeated AddressProperty addresses = 4;
}
message ListAccountsRequest {
// An optional filter to only return accounts matching this name.
string name = 1;
@ -404,6 +448,7 @@ message ListAccountsRequest {
// An optional filter to only return accounts matching this address type.
AddressType address_type = 2;
}
message ListAccountsResponse {
repeated Account accounts = 1;
}
@ -418,6 +463,20 @@ message RequiredReserveResponse {
int64 required_reserve = 1;
}
message ListAddressesRequest {
// An optional filter to only return addresses matching this account.
string account_name = 1;
// An optional flag to return LND's custom accounts (Purpose=1017)
// public key along with other addresses.
bool show_custom_accounts = 2;
}
message ListAddressesResponse {
// A list of all the accounts and their addresses.
repeated AccountWithAddresses account_with_addresses = 1;
}
message ImportAccountRequest {
// A name to identify the account with.
string name = 1;

View File

@ -130,6 +130,45 @@
]
}
},
"/v2/wallet/addresses": {
"get": {
"summary": "ListAddresses retrieves all the addresses along with their balance. An\naccount name filter can be provided to filter through all of the\nwallet accounts and return the addresses of only those matching.",
"operationId": "WalletKit_ListAddresses",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/walletrpcListAddressesResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "account_name",
"description": "An optional filter to only return addresses matching this account.",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "show_custom_accounts",
"description": "An optional flag to return LND's custom accounts (Purpose=1017)\npublic key along with other addresses.",
"in": "query",
"required": false,
"type": "boolean"
}
],
"tags": [
"WalletKit"
]
}
},
"/v2/wallet/bumpfee": {
"post": {
"summary": "BumpFee bumps the fee of an arbitrary input within a transaction. This RPC\ntakes a different approach than bitcoind's bumpfee command. lnd has a\ncentral batching engine in which inputs with similar fee rates are batched\ntogether to save on transaction fees. Due to this, we cannot rely on\nbumping the fee on a specific transaction, since transactions can change at\nany point with the addition of new inputs. The list of inputs that\ncurrently exist within lnd's central batching engine can be retrieved\nthrough the PendingSweeps RPC.",
@ -1008,7 +1047,7 @@
},
"address_type": {
"$ref": "#/definitions/walletrpcAddressType",
"title": "The type of addresses the account supports.\nAddressType | External Branch | Internal Branch\n---------------------------------------------------------------------\nWITNESS_PUBKEY_HASH | P2WPKH | P2WPKH\nNESTED_WITNESS_PUBKEY_HASH | NP2WPKH | NP2WPKH\nHYBRID_NESTED_WITNESS_PUBKEY_HASH | NP2WPKH | P2WPKH"
"description": "The type of addresses the account supports."
},
"extended_public_key": {
"type": "string",
@ -1039,6 +1078,30 @@
}
}
},
"walletrpcAccountWithAddresses": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name used to identify the account."
},
"address_type": {
"$ref": "#/definitions/walletrpcAddressType",
"description": "The type of addresses the account supports."
},
"derivation_path": {
"type": "string",
"description": "The derivation path corresponding to the account public key. This will\nalways be empty for the default imported account in which single public keys\nare imported into."
},
"addresses": {
"type": "array",
"items": {
"$ref": "#/definitions/walletrpcAddressProperty"
},
"description": "List of address, its type internal/external \u0026 balance.\nNote that the order of addresses will be random and not according to the\nderivation index, since that information is not stored by the underlying\nwallet."
}
}
},
"walletrpcAddrRequest": {
"type": "object",
"properties": {
@ -1065,6 +1128,24 @@
}
}
},
"walletrpcAddressProperty": {
"type": "object",
"properties": {
"address": {
"type": "string",
"description": "The address encoded using the appropriate format depending on the\naddress type (base58, bech32, bech32m).\n\nNote that lnd's internal/custom keys for channels and other\nfunctionality are derived from the same scope. Since they\naren't really used as addresses and will never have an\non-chain balance, we'll show the public key instead (only if\nthe show_custom_accounts flag is provided)."
},
"is_internal": {
"type": "boolean",
"description": "Denotes if the address is a change address."
},
"balance": {
"type": "string",
"format": "int64",
"description": "The balance of the address."
}
}
},
"walletrpcAddressType": {
"type": "string",
"enum": [
@ -1347,6 +1428,18 @@
}
}
},
"walletrpcListAddressesResponse": {
"type": "object",
"properties": {
"account_with_addresses": {
"type": "array",
"items": {
"$ref": "#/definitions/walletrpcAccountWithAddresses"
},
"description": "A list of all the accounts and their addresses."
}
}
},
"walletrpcListLeasesResponse": {
"type": "object",
"properties": {

View File

@ -57,6 +57,8 @@ http:
get: "/v2/wallet/accounts"
- selector: walletrpc.WalletKit.RequiredReserve
get: "/v2/wallet/reserve"
- selector: walletrpc.WalletKit.ListAddresses
get: "/v2/wallet/addresses"
- selector: walletrpc.WalletKit.ImportAccount
post: "/v2/wallet/accounts/import"
body: "*"

View File

@ -63,6 +63,11 @@ type WalletKitClient interface {
//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)
//
//ListAddresses retrieves all the addresses along with their balance. An
//account name filter can be provided to filter through all of the
//wallet accounts and return the addresses of only those matching.
ListAddresses(ctx context.Context, in *ListAddressesRequest, opts ...grpc.CallOption) (*ListAddressesResponse, 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
@ -295,6 +300,15 @@ func (c *walletKitClient) RequiredReserve(ctx context.Context, in *RequiredReser
return out, nil
}
func (c *walletKitClient) ListAddresses(ctx context.Context, in *ListAddressesRequest, opts ...grpc.CallOption) (*ListAddressesResponse, error) {
out := new(ListAddressesResponse)
err := c.cc.Invoke(ctx, "/walletrpc.WalletKit/ListAddresses", 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...)
@ -451,6 +465,11 @@ type WalletKitServer interface {
//scales with the number of public anchor channels but is capped at a maximum.
RequiredReserve(context.Context, *RequiredReserveRequest) (*RequiredReserveResponse, error)
//
//ListAddresses retrieves all the addresses along with their balance. An
//account name filter can be provided to filter through all of the
//wallet accounts and return the addresses of only those matching.
ListAddresses(context.Context, *ListAddressesRequest) (*ListAddressesResponse, 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
@ -626,6 +645,9 @@ func (UnimplementedWalletKitServer) ListAccounts(context.Context, *ListAccountsR
func (UnimplementedWalletKitServer) RequiredReserve(context.Context, *RequiredReserveRequest) (*RequiredReserveResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method RequiredReserve not implemented")
}
func (UnimplementedWalletKitServer) ListAddresses(context.Context, *ListAddressesRequest) (*ListAddressesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListAddresses not implemented")
}
func (UnimplementedWalletKitServer) ImportAccount(context.Context, *ImportAccountRequest) (*ImportAccountResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ImportAccount not implemented")
}
@ -837,6 +859,24 @@ func _WalletKit_RequiredReserve_Handler(srv interface{}, ctx context.Context, de
return interceptor(ctx, in, info, handler)
}
func _WalletKit_ListAddresses_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListAddressesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WalletKitServer).ListAddresses(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/walletrpc.WalletKit/ListAddresses",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WalletKitServer).ListAddresses(ctx, req.(*ListAddressesRequest))
}
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 {
@ -1096,6 +1136,10 @@ var WalletKit_ServiceDesc = grpc.ServiceDesc{
MethodName: "RequiredReserve",
Handler: _WalletKit_RequiredReserve_Handler,
},
{
MethodName: "ListAddresses",
Handler: _WalletKit_ListAddresses_Handler,
},
{
MethodName: "ImportAccount",
Handler: _WalletKit_ImportAccount_Handler,

View File

@ -13,6 +13,7 @@ import (
"math"
"os"
"path/filepath"
"sort"
"time"
"github.com/btcsuite/btcd/btcec/v2"
@ -120,6 +121,10 @@ var (
Entity: "onchain",
Action: "read",
}},
"/walletrpc.WalletKit/ListAddresses": {{
Entity: "onchain",
Action: "read",
}},
"/walletrpc.WalletKit/FundPsbt": {{
Entity: "onchain",
Action: "write",
@ -368,6 +373,7 @@ func (w *WalletKit) ListUnspent(ctx context.Context,
utxos, err = w.cfg.Wallet.ListUnspentWitness(
minConfs, maxConfs, req.Account,
)
return err
})
if err != nil {
@ -1416,6 +1422,38 @@ func marshalWalletAccount(internalScope waddrmgr.KeyScope,
return rpcAccount, nil
}
// marshalWalletAddressList converts the list of address into its RPC
// representation.
func marshalWalletAddressList(w *WalletKit, account *waddrmgr.AccountProperties,
addressList []lnwallet.AddressProperty) (*AccountWithAddresses, error) {
// Get the RPC representation of account.
rpcAccount, err := marshalWalletAccount(
w.internalScope(), account,
)
if err != nil {
return nil, err
}
addresses := make([]*AddressProperty, len(addressList))
for idx, addr := range addressList {
addresses[idx] = &AddressProperty{
Address: addr.Address,
IsInternal: addr.Internal,
Balance: int64(addr.Balance),
}
}
rpcAddressList := &AccountWithAddresses{
Name: rpcAccount.Name,
AddressType: rpcAccount.AddressType,
DerivationPath: rpcAccount.DerivationPath,
Addresses: addresses,
}
return rpcAddressList, nil
}
// ListAccounts retrieves all accounts belonging to the wallet by default. A
// name and key scope filter can be provided to filter through all of the wallet
// accounts and return only those matching.
@ -1494,6 +1532,61 @@ func (w *WalletKit) RequiredReserve(ctx context.Context,
}, nil
}
// ListAddresses retrieves all the addresses along with their balance. An
// account name filter can be provided to filter through all of the
// wallet accounts and return the addresses of only those matching.
func (w *WalletKit) ListAddresses(ctx context.Context,
req *ListAddressesRequest) (*ListAddressesResponse, error) {
addressLists, err := w.cfg.Wallet.ListAddresses(
req.AccountName,
req.ShowCustomAccounts,
)
if err != nil {
return nil, err
}
// Create a slice of accounts from addressLists map.
accounts := make([]*waddrmgr.AccountProperties, 0, len(addressLists))
for account := range addressLists {
accounts = append(accounts, account)
}
// Sort the accounts by derivation path.
sort.Slice(accounts, func(i, j int) bool {
scopeI := accounts[i].KeyScope
scopeJ := accounts[j].KeyScope
if scopeI.Purpose == scopeJ.Purpose {
if scopeI.Coin == scopeJ.Coin {
acntNumI := accounts[i].AccountNumber
acntNumJ := accounts[j].AccountNumber
return acntNumI < acntNumJ
}
return scopeI.Coin < scopeJ.Coin
}
return scopeI.Purpose < scopeJ.Purpose
})
rpcAddressLists := make([]*AccountWithAddresses, 0, len(addressLists))
for _, account := range accounts {
addressList := addressLists[account]
rpcAddressList, err := marshalWalletAddressList(
w, account, addressList,
)
if err != nil {
return nil, err
}
rpcAddressLists = append(rpcAddressLists, rpcAddressList)
}
return &ListAddressesResponse{
AccountWithAddresses: rpcAddressLists,
}, nil
}
// parseAddrType parses an address type from its RPC representation to a
// *waddrmgr.AddressType.
func parseAddrType(addrType AddressType,