mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-06-12 09:52:14 +02:00
Merge pull request #8998 from Abdulkbk/trx-pagination
pagination: add pagination to wallet transactions
This commit is contained in:
commit
94f7ed46de
@ -2074,6 +2074,20 @@ var listChainTxnsCommand = cli.Command{
|
|||||||
"transactions until the chain tip, including " +
|
"transactions until the chain tip, including " +
|
||||||
"unconfirmed, set this value to -1",
|
"unconfirmed, set this value to -1",
|
||||||
},
|
},
|
||||||
|
cli.UintFlag{
|
||||||
|
Name: "index_offset",
|
||||||
|
Usage: "the index of a transaction that will be " +
|
||||||
|
"used in a query to determine which " +
|
||||||
|
"transaction should be returned in the " +
|
||||||
|
"response",
|
||||||
|
},
|
||||||
|
cli.IntFlag{
|
||||||
|
Name: "max_transactions",
|
||||||
|
Usage: "(optional) the max number of transactions to " +
|
||||||
|
"return; leave at default of 0 to return " +
|
||||||
|
"all transactions",
|
||||||
|
Value: 0,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Description: `
|
Description: `
|
||||||
List all transactions an address of the wallet was involved in.
|
List all transactions an address of the wallet was involved in.
|
||||||
@ -2096,7 +2110,10 @@ func listChainTxns(ctx *cli.Context) error {
|
|||||||
client, cleanUp := getClient(ctx)
|
client, cleanUp := getClient(ctx)
|
||||||
defer cleanUp()
|
defer cleanUp()
|
||||||
|
|
||||||
req := &lnrpc.GetTransactionsRequest{}
|
req := &lnrpc.GetTransactionsRequest{
|
||||||
|
IndexOffset: uint32(ctx.Uint64("index_offset")),
|
||||||
|
MaxTransactions: uint32(ctx.Uint64("max_transactions")),
|
||||||
|
}
|
||||||
|
|
||||||
if ctx.IsSet("start_height") {
|
if ctx.IsSet("start_height") {
|
||||||
req.StartHeight = int32(ctx.Int64("start_height"))
|
req.StartHeight = int32(ctx.Int64("start_height"))
|
||||||
|
@ -62,6 +62,8 @@
|
|||||||
|
|
||||||
# New Features
|
# New Features
|
||||||
## Functional Enhancements
|
## Functional Enhancements
|
||||||
|
* [Add ability](https://github.com/lightningnetwork/lnd/pull/8998) to paginate
|
||||||
|
wallet transactions.
|
||||||
## RPC Additions
|
## RPC Additions
|
||||||
|
|
||||||
* [Add a new rpc endpoint](https://github.com/lightningnetwork/lnd/pull/8843)
|
* [Add a new rpc endpoint](https://github.com/lightningnetwork/lnd/pull/8843)
|
||||||
@ -196,6 +198,7 @@ The underlying functionality between those two options remain the same.
|
|||||||
|
|
||||||
# Contributors (Alphabetical Order)
|
# Contributors (Alphabetical Order)
|
||||||
|
|
||||||
|
* Abdullahi Yunus
|
||||||
* Animesh Bilthare
|
* Animesh Bilthare
|
||||||
* Boris Nagaev
|
* Boris Nagaev
|
||||||
* CharlieZKSmith
|
* CharlieZKSmith
|
||||||
|
@ -2068,6 +2068,12 @@ type GetTransactionsRequest struct {
|
|||||||
EndHeight int32 `protobuf:"varint,2,opt,name=end_height,json=endHeight,proto3" json:"end_height,omitempty"`
|
EndHeight int32 `protobuf:"varint,2,opt,name=end_height,json=endHeight,proto3" json:"end_height,omitempty"`
|
||||||
// An optional filter to only include transactions relevant to an account.
|
// An optional filter to only include transactions relevant to an account.
|
||||||
Account string `protobuf:"bytes,3,opt,name=account,proto3" json:"account,omitempty"`
|
Account string `protobuf:"bytes,3,opt,name=account,proto3" json:"account,omitempty"`
|
||||||
|
// The index of a transaction that will be used in a query to determine which
|
||||||
|
// transaction should be returned in the response.
|
||||||
|
IndexOffset uint32 `protobuf:"varint,4,opt,name=index_offset,json=indexOffset,proto3" json:"index_offset,omitempty"`
|
||||||
|
// The maximal number of transactions returned in the response to this query.
|
||||||
|
// This value should be set to 0 to return all transactions.
|
||||||
|
MaxTransactions uint32 `protobuf:"varint,5,opt,name=max_transactions,json=maxTransactions,proto3" json:"max_transactions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetTransactionsRequest) Reset() {
|
func (x *GetTransactionsRequest) Reset() {
|
||||||
@ -2123,6 +2129,20 @@ func (x *GetTransactionsRequest) GetAccount() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *GetTransactionsRequest) GetIndexOffset() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.IndexOffset
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetTransactionsRequest) GetMaxTransactions() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.MaxTransactions
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
type TransactionDetails struct {
|
type TransactionDetails struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@ -2130,6 +2150,12 @@ type TransactionDetails struct {
|
|||||||
|
|
||||||
// The list of transactions relevant to the wallet.
|
// The list of transactions relevant to the wallet.
|
||||||
Transactions []*Transaction `protobuf:"bytes,1,rep,name=transactions,proto3" json:"transactions,omitempty"`
|
Transactions []*Transaction `protobuf:"bytes,1,rep,name=transactions,proto3" json:"transactions,omitempty"`
|
||||||
|
// The index of the last item in the set of returned transactions. This can be
|
||||||
|
// used to seek further, pagination style.
|
||||||
|
LastIndex uint64 `protobuf:"varint,2,opt,name=last_index,json=lastIndex,proto3" json:"last_index,omitempty"`
|
||||||
|
// The index of the last item in the set of returned transactions. This can be
|
||||||
|
// used to seek backwards, pagination style.
|
||||||
|
FirstIndex uint64 `protobuf:"varint,3,opt,name=first_index,json=firstIndex,proto3" json:"first_index,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *TransactionDetails) Reset() {
|
func (x *TransactionDetails) Reset() {
|
||||||
@ -2171,6 +2197,20 @@ func (x *TransactionDetails) GetTransactions() []*Transaction {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *TransactionDetails) GetLastIndex() uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.LastIndex
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TransactionDetails) GetFirstIndex() uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.FirstIndex
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
type FeeLimit struct {
|
type FeeLimit struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@ -18558,20 +18598,29 @@ var file_lightning_proto_rawDesc = []byte{
|
|||||||
0x75, 0x73, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x0c, 0x20, 0x03,
|
0x75, 0x73, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x0c, 0x20, 0x03,
|
||||||
0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x65, 0x76, 0x69,
|
0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x65, 0x76, 0x69,
|
||||||
0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x11, 0x70, 0x72, 0x65,
|
0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x11, 0x70, 0x72, 0x65,
|
||||||
0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, 0x74,
|
0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, 0xc2,
|
||||||
0x0a, 0x16, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
|
||||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x72,
|
0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x74, 0x61,
|
||||||
0x74, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b,
|
0x72, 0x74, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||||
0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x65,
|
0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1d, 0x0a, 0x0a,
|
||||||
0x6e, 0x64, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52,
|
0x65, 0x6e, 0x64, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05,
|
||||||
0x09, 0x65, 0x6e, 0x64, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63,
|
0x52, 0x09, 0x65, 0x6e, 0x64, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61,
|
||||||
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63,
|
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63,
|
||||||
0x6f, 0x75, 0x6e, 0x74, 0x22, 0x4c, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
|
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6f,
|
||||||
|
0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x69, 0x6e, 0x64,
|
||||||
|
0x65, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f,
|
||||||
|
0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01,
|
||||||
|
0x28, 0x0d, 0x52, 0x0f, 0x6d, 0x61, 0x78, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69,
|
||||||
|
0x6f, 0x6e, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
|
||||||
0x69, 0x6f, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x36, 0x0a, 0x0c, 0x74, 0x72,
|
0x69, 0x6f, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x36, 0x0a, 0x0c, 0x74, 0x72,
|
||||||
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
|
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
|
||||||
0x32, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
|
0x32, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
|
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
|
||||||
0x6e, 0x73, 0x22, 0x68, 0x0a, 0x08, 0x46, 0x65, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x16,
|
0x6e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78,
|
||||||
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65,
|
||||||
|
0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78,
|
||||||
|
0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x49, 0x6e, 0x64,
|
||||||
|
0x65, 0x78, 0x22, 0x68, 0x0a, 0x08, 0x46, 0x65, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x16,
|
||||||
0x0a, 0x05, 0x66, 0x69, 0x78, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52,
|
0x0a, 0x05, 0x66, 0x69, 0x78, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52,
|
||||||
0x05, 0x66, 0x69, 0x78, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0a, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f,
|
0x05, 0x66, 0x69, 0x78, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0a, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f,
|
||||||
0x6d, 0x73, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x09, 0x66, 0x69,
|
0x6d, 0x73, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x09, 0x66, 0x69,
|
||||||
|
@ -757,11 +757,35 @@ message GetTransactionsRequest {
|
|||||||
|
|
||||||
// An optional filter to only include transactions relevant to an account.
|
// An optional filter to only include transactions relevant to an account.
|
||||||
string account = 3;
|
string account = 3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The index of a transaction that will be used in a query to determine which
|
||||||
|
transaction should be returned in the response.
|
||||||
|
*/
|
||||||
|
uint32 index_offset = 4;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The maximal number of transactions returned in the response to this query.
|
||||||
|
This value should be set to 0 to return all transactions.
|
||||||
|
*/
|
||||||
|
uint32 max_transactions = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TransactionDetails {
|
message TransactionDetails {
|
||||||
// The list of transactions relevant to the wallet.
|
// The list of transactions relevant to the wallet.
|
||||||
repeated Transaction transactions = 1;
|
repeated Transaction transactions = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The index of the last item in the set of returned transactions. This can be
|
||||||
|
used to seek further, pagination style.
|
||||||
|
*/
|
||||||
|
uint64 last_index = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The index of the last item in the set of returned transactions. This can be
|
||||||
|
used to seek backwards, pagination style.
|
||||||
|
*/
|
||||||
|
uint64 first_index = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message FeeLimit {
|
message FeeLimit {
|
||||||
|
@ -2591,6 +2591,22 @@
|
|||||||
"in": "query",
|
"in": "query",
|
||||||
"required": false,
|
"required": false,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_offset",
|
||||||
|
"description": "The index of a transaction that will be used in a query to determine which\ntransaction should be returned in the response.",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "max_transactions",
|
||||||
|
"description": "The maximal number of transactions returned in the response to this query.\nThis value should be set to 0 to return all transactions.",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
@ -2774,6 +2790,22 @@
|
|||||||
"in": "query",
|
"in": "query",
|
||||||
"required": false,
|
"required": false,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_offset",
|
||||||
|
"description": "The index of a transaction that will be used in a query to determine which\ntransaction should be returned in the response.",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "max_transactions",
|
||||||
|
"description": "The maximal number of transactions returned in the response to this query.\nThis value should be set to 0 to return all transactions.",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
@ -7492,6 +7524,16 @@
|
|||||||
"$ref": "#/definitions/lnrpcTransaction"
|
"$ref": "#/definitions/lnrpcTransaction"
|
||||||
},
|
},
|
||||||
"description": "The list of transactions relevant to the wallet."
|
"description": "The list of transactions relevant to the wallet."
|
||||||
|
},
|
||||||
|
"last_index": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uint64",
|
||||||
|
"description": "The index of the last item in the set of returned transactions. This can be\nused to seek further, pagination style."
|
||||||
|
},
|
||||||
|
"first_index": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uint64",
|
||||||
|
"description": "The index of the last item in the set of returned transactions. This can be\nused to seek backwards, pagination style."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -117,9 +117,13 @@ func RPCTransaction(tx *lnwallet.TransactionDetail) *Transaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RPCTransactionDetails returns a set of rpc transaction details.
|
// RPCTransactionDetails returns a set of rpc transaction details.
|
||||||
func RPCTransactionDetails(txns []*lnwallet.TransactionDetail) *TransactionDetails {
|
func RPCTransactionDetails(txns []*lnwallet.TransactionDetail, firstIdx,
|
||||||
|
lastIdx uint64) *TransactionDetails {
|
||||||
|
|
||||||
txDetails := &TransactionDetails{
|
txDetails := &TransactionDetails{
|
||||||
Transactions: make([]*Transaction, len(txns)),
|
Transactions: make([]*Transaction, len(txns)),
|
||||||
|
FirstIndex: firstIdx,
|
||||||
|
LastIndex: lastIdx,
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tx := range txns {
|
for i, tx := range txns {
|
||||||
|
@ -1166,6 +1166,16 @@
|
|||||||
"$ref": "#/definitions/lnrpcTransaction"
|
"$ref": "#/definitions/lnrpcTransaction"
|
||||||
},
|
},
|
||||||
"description": "The list of transactions relevant to the wallet."
|
"description": "The list of transactions relevant to the wallet."
|
||||||
|
},
|
||||||
|
"last_index": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uint64",
|
||||||
|
"description": "The index of the last item in the set of returned transactions. This can be\nused to seek further, pagination style."
|
||||||
|
},
|
||||||
|
"first_index": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uint64",
|
||||||
|
"description": "The index of the last item in the set of returned transactions. This can be\nused to seek backwards, pagination style."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1376,9 +1376,9 @@ func (w *WalletKit) ListSweeps(ctx context.Context,
|
|||||||
// can match our list of sweeps against the list of transactions that
|
// can match our list of sweeps against the list of transactions that
|
||||||
// the wallet is still tracking. Sweeps are currently always swept to
|
// the wallet is still tracking. Sweeps are currently always swept to
|
||||||
// the default wallet account.
|
// the default wallet account.
|
||||||
transactions, err := w.cfg.Wallet.ListTransactionDetails(
|
txns, firstIdx, lastIdx, err := w.cfg.Wallet.ListTransactionDetails(
|
||||||
in.StartHeight, btcwallet.UnconfirmedHeight,
|
in.StartHeight, btcwallet.UnconfirmedHeight,
|
||||||
lnwallet.DefaultAccountName,
|
lnwallet.DefaultAccountName, 0, 0,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -1389,7 +1389,7 @@ func (w *WalletKit) ListSweeps(ctx context.Context,
|
|||||||
txDetails []*lnwallet.TransactionDetail
|
txDetails []*lnwallet.TransactionDetail
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, tx := range transactions {
|
for _, tx := range txns {
|
||||||
_, ok := sweepTxns[tx.Hash.String()]
|
_, ok := sweepTxns[tx.Hash.String()]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
@ -1408,7 +1408,7 @@ func (w *WalletKit) ListSweeps(ctx context.Context,
|
|||||||
return &ListSweepsResponse{
|
return &ListSweepsResponse{
|
||||||
Sweeps: &ListSweepsResponse_TransactionDetails{
|
Sweeps: &ListSweepsResponse_TransactionDetails{
|
||||||
TransactionDetails: lnrpc.RPCTransactionDetails(
|
TransactionDetails: lnrpc.RPCTransactionDetails(
|
||||||
txDetails,
|
txDetails, firstIdx, lastIdx,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -187,9 +187,10 @@ func (w *WalletController) ListUnspentWitness(int32, int32,
|
|||||||
|
|
||||||
// ListTransactionDetails currently returns dummy values.
|
// ListTransactionDetails currently returns dummy values.
|
||||||
func (w *WalletController) ListTransactionDetails(int32, int32,
|
func (w *WalletController) ListTransactionDetails(int32, int32,
|
||||||
string) ([]*lnwallet.TransactionDetail, error) {
|
string, uint32, uint32) ([]*lnwallet.TransactionDetail,
|
||||||
|
uint64, uint64, error) {
|
||||||
|
|
||||||
return nil, nil
|
return nil, 0, 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LeaseOutput returns the current time and a nil error.
|
// LeaseOutput returns the current time and a nil error.
|
||||||
|
@ -1554,7 +1554,9 @@ func unminedTransactionsToDetail(
|
|||||||
//
|
//
|
||||||
// This is a part of the WalletController interface.
|
// This is a part of the WalletController interface.
|
||||||
func (b *BtcWallet) ListTransactionDetails(startHeight, endHeight int32,
|
func (b *BtcWallet) ListTransactionDetails(startHeight, endHeight int32,
|
||||||
accountFilter string) ([]*lnwallet.TransactionDetail, error) {
|
accountFilter string, indexOffset uint32,
|
||||||
|
maxTransactions uint32) ([]*lnwallet.TransactionDetail, uint64, uint64,
|
||||||
|
error) {
|
||||||
|
|
||||||
// Grab the best block the wallet knows of, we'll use this to calculate
|
// Grab the best block the wallet knows of, we'll use this to calculate
|
||||||
// # of confirmations shortly below.
|
// # of confirmations shortly below.
|
||||||
@ -1566,7 +1568,7 @@ func (b *BtcWallet) ListTransactionDetails(startHeight, endHeight int32,
|
|||||||
stop := base.NewBlockIdentifierFromHeight(endHeight)
|
stop := base.NewBlockIdentifierFromHeight(endHeight)
|
||||||
txns, err := b.wallet.GetTransactions(start, stop, accountFilter, nil)
|
txns, err := b.wallet.GetTransactions(start, stop, accountFilter, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
txDetails := make([]*lnwallet.TransactionDetail, 0,
|
txDetails := make([]*lnwallet.TransactionDetail, 0,
|
||||||
@ -1580,7 +1582,7 @@ func (b *BtcWallet) ListTransactionDetails(startHeight, endHeight int32,
|
|||||||
currentHeight, blockPackage, b.netParams,
|
currentHeight, blockPackage, b.netParams,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
txDetails = append(txDetails, details...)
|
txDetails = append(txDetails, details...)
|
||||||
@ -1588,13 +1590,38 @@ func (b *BtcWallet) ListTransactionDetails(startHeight, endHeight int32,
|
|||||||
for _, tx := range txns.UnminedTransactions {
|
for _, tx := range txns.UnminedTransactions {
|
||||||
detail, err := unminedTransactionsToDetail(tx, b.netParams)
|
detail, err := unminedTransactionsToDetail(tx, b.netParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
txDetails = append(txDetails, detail)
|
txDetails = append(txDetails, detail)
|
||||||
}
|
}
|
||||||
|
|
||||||
return txDetails, nil
|
// Return empty transaction list, if offset is more than all
|
||||||
|
// transactions.
|
||||||
|
if int(indexOffset) >= len(txDetails) {
|
||||||
|
txDetails = []*lnwallet.TransactionDetail{}
|
||||||
|
|
||||||
|
return txDetails, 0, 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
end := indexOffset + maxTransactions
|
||||||
|
|
||||||
|
// If maxTransactions is set to 0, then we'll return all transactions
|
||||||
|
// starting from the offset.
|
||||||
|
if maxTransactions == 0 {
|
||||||
|
end = uint32(len(txDetails))
|
||||||
|
txDetails = txDetails[indexOffset:end]
|
||||||
|
|
||||||
|
return txDetails, uint64(indexOffset), uint64(end - 1), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if end > uint32(len(txDetails)) {
|
||||||
|
end = uint32(len(txDetails))
|
||||||
|
}
|
||||||
|
|
||||||
|
txDetails = txDetails[indexOffset:end]
|
||||||
|
|
||||||
|
return txDetails, uint64(indexOffset), uint64(end - 1), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// txSubscriptionClient encapsulates the transaction notification client from
|
// txSubscriptionClient encapsulates the transaction notification client from
|
||||||
|
@ -402,7 +402,9 @@ type WalletController interface {
|
|||||||
// retrieve the transactions relevant to a specific account. When
|
// retrieve the transactions relevant to a specific account. When
|
||||||
// empty, transactions of all wallet accounts are returned.
|
// empty, transactions of all wallet accounts are returned.
|
||||||
ListTransactionDetails(startHeight, endHeight int32,
|
ListTransactionDetails(startHeight, endHeight int32,
|
||||||
accountFilter string) ([]*TransactionDetail, error)
|
accountFilter string, indexOffset uint32,
|
||||||
|
maxTransactions uint32) ([]*TransactionDetail, uint64, uint64,
|
||||||
|
error)
|
||||||
|
|
||||||
// LeaseOutput locks an output to the given ID, preventing it from being
|
// LeaseOutput locks an output to the given ID, preventing it from being
|
||||||
// available for any future coin selection attempts. The absolute time
|
// available for any future coin selection attempts. The absolute time
|
||||||
|
@ -198,9 +198,9 @@ func (w *mockWalletController) ListUnspentWitness(int32, int32,
|
|||||||
|
|
||||||
// ListTransactionDetails currently returns dummy values.
|
// ListTransactionDetails currently returns dummy values.
|
||||||
func (w *mockWalletController) ListTransactionDetails(int32, int32,
|
func (w *mockWalletController) ListTransactionDetails(int32, int32,
|
||||||
string) ([]*TransactionDetail, error) {
|
string, uint32, uint32) ([]*TransactionDetail, uint64, uint64, error) {
|
||||||
|
|
||||||
return nil, nil
|
return nil, 0, 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LeaseOutput returns the current time and a nil error.
|
// LeaseOutput returns the current time and a nil error.
|
||||||
|
@ -199,7 +199,9 @@ func assertTxInWallet(t *testing.T, w *lnwallet.LightningWallet,
|
|||||||
// We'll fetch all of our transaction and go through each one until
|
// We'll fetch all of our transaction and go through each one until
|
||||||
// finding the expected transaction with its expected confirmation
|
// finding the expected transaction with its expected confirmation
|
||||||
// status.
|
// status.
|
||||||
txs, err := w.ListTransactionDetails(0, btcwallet.UnconfirmedHeight, "")
|
txs, _, _, err := w.ListTransactionDetails(
|
||||||
|
0, btcwallet.UnconfirmedHeight, "", 0, 1000,
|
||||||
|
)
|
||||||
require.NoError(t, err, "unable to retrieve transactions")
|
require.NoError(t, err, "unable to retrieve transactions")
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
if tx.Hash != txHash {
|
if tx.Hash != txHash {
|
||||||
@ -1101,8 +1103,8 @@ func testListTransactionDetails(miner *rpctest.Harness,
|
|||||||
// should be confirmed.
|
// should be confirmed.
|
||||||
err = waitForWalletSync(miner, alice)
|
err = waitForWalletSync(miner, alice)
|
||||||
require.NoError(t, err, "Couldn't sync Alice's wallet")
|
require.NoError(t, err, "Couldn't sync Alice's wallet")
|
||||||
txDetails, err := alice.ListTransactionDetails(
|
txDetails, _, _, err := alice.ListTransactionDetails(
|
||||||
startHeight, chainTip, "",
|
startHeight, chainTip, "", 0, 1000,
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "unable to fetch tx details")
|
require.NoError(t, err, "unable to fetch tx details")
|
||||||
|
|
||||||
@ -1213,8 +1215,8 @@ func testListTransactionDetails(miner *rpctest.Harness,
|
|||||||
// unconfirmed transactions. The transaction above should be included
|
// unconfirmed transactions. The transaction above should be included
|
||||||
// with a confirmation height of 0, indicating that it has not been
|
// with a confirmation height of 0, indicating that it has not been
|
||||||
// mined yet.
|
// mined yet.
|
||||||
txDetails, err = alice.ListTransactionDetails(
|
txDetails, _, _, err = alice.ListTransactionDetails(
|
||||||
chainTip, btcwallet.UnconfirmedHeight, "",
|
chainTip, btcwallet.UnconfirmedHeight, "", 0, 1000,
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "unable to fetch tx details")
|
require.NoError(t, err, "unable to fetch tx details")
|
||||||
var mempoolTxFound bool
|
var mempoolTxFound bool
|
||||||
@ -1266,7 +1268,9 @@ func testListTransactionDetails(miner *rpctest.Harness,
|
|||||||
// transactions from the last block.
|
// transactions from the last block.
|
||||||
err = waitForWalletSync(miner, alice)
|
err = waitForWalletSync(miner, alice)
|
||||||
require.NoError(t, err, "Couldn't sync Alice's wallet")
|
require.NoError(t, err, "Couldn't sync Alice's wallet")
|
||||||
txDetails, err = alice.ListTransactionDetails(chainTip, chainTip, "")
|
txDetails, _, _, err = alice.ListTransactionDetails(
|
||||||
|
chainTip, chainTip, "", 0, 1000,
|
||||||
|
)
|
||||||
require.NoError(t, err, "unable to fetch tx details")
|
require.NoError(t, err, "unable to fetch tx details")
|
||||||
var burnTxFound bool
|
var burnTxFound bool
|
||||||
for _, txDetail := range txDetails {
|
for _, txDetail := range txDetails {
|
||||||
@ -1307,13 +1311,116 @@ func testListTransactionDetails(miner *rpctest.Harness,
|
|||||||
|
|
||||||
// Query for transactions only in the latest block. We do not expect
|
// Query for transactions only in the latest block. We do not expect
|
||||||
// any transactions to be returned.
|
// any transactions to be returned.
|
||||||
txDetails, err = alice.ListTransactionDetails(chainTip, chainTip, "")
|
txDetails, _, _, err = alice.ListTransactionDetails(
|
||||||
|
chainTip, chainTip, "", 0, 1000,
|
||||||
|
)
|
||||||
require.NoError(t, err, "unexpected error")
|
require.NoError(t, err, "unexpected error")
|
||||||
if len(txDetails) != 0 {
|
if len(txDetails) != 0 {
|
||||||
t.Fatalf("expected 0 transactions, got: %v", len(txDetails))
|
t.Fatalf("expected 0 transactions, got: %v", len(txDetails))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testListTransactionDetailsOffset(miner *rpctest.Harness,
|
||||||
|
alice, _ *lnwallet.LightningWallet, t *testing.T) {
|
||||||
|
|
||||||
|
// Create 5 new outputs spendable by the wallet.
|
||||||
|
const numTxns = 5
|
||||||
|
const outputAmt = btcutil.SatoshiPerBitcoin
|
||||||
|
isOurAddress := make(map[string]bool)
|
||||||
|
txids := make(map[chainhash.Hash]struct{})
|
||||||
|
for i := 0; i < numTxns; i++ {
|
||||||
|
addr, err := alice.NewAddress(
|
||||||
|
lnwallet.WitnessPubKey, false,
|
||||||
|
lnwallet.DefaultAccountName,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
isOurAddress[addr.EncodeAddress()] = true
|
||||||
|
script, err := txscript.PayToAddrScript(addr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
output := &wire.TxOut{
|
||||||
|
Value: outputAmt,
|
||||||
|
PkScript: script,
|
||||||
|
}
|
||||||
|
txid, err := miner.SendOutputs([]*wire.TxOut{output}, 2500)
|
||||||
|
require.NoError(t, err)
|
||||||
|
txids[*txid] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the miner's current best block height before we mine blocks.
|
||||||
|
_, startHeight, err := miner.Client.GetBestBlock()
|
||||||
|
require.NoError(t, err, "cannot get best block")
|
||||||
|
|
||||||
|
// Generate 10 blocks to mine all the transactions created above.
|
||||||
|
const numBlocksMined = 10
|
||||||
|
_, err = miner.Client.Generate(numBlocksMined)
|
||||||
|
require.NoError(t, err, "unable to mine blocks")
|
||||||
|
|
||||||
|
// Our new best block height should be our start height + the number of
|
||||||
|
// blocks we just mined.
|
||||||
|
chainTip := startHeight + numBlocksMined
|
||||||
|
|
||||||
|
err = waitForWalletSync(miner, alice)
|
||||||
|
require.NoError(t, err, "Couldn't sync Alice's wallet")
|
||||||
|
|
||||||
|
// Query for transactions, setting max_transactions to 5. We expect 5
|
||||||
|
// transactions to be returned.
|
||||||
|
txDetails, firstIdx, lastIdx, err := alice.ListTransactionDetails(
|
||||||
|
startHeight, chainTip, "", 0, 5,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, txDetails, 5)
|
||||||
|
require.EqualValues(t, 0, firstIdx)
|
||||||
|
require.EqualValues(t, 4, lastIdx)
|
||||||
|
|
||||||
|
// Query for transactions, setting max_transactions to less than the
|
||||||
|
// number of transactions we have (5).
|
||||||
|
txDetails, _, _, err = alice.ListTransactionDetails(
|
||||||
|
startHeight, chainTip, "", 0, 1,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, txDetails, 1)
|
||||||
|
|
||||||
|
// Query for transactions, setting indexOffset to 5 (equal to number
|
||||||
|
// of transactions we have) and max_transactions to 0.
|
||||||
|
txDetails, _, _, err = alice.ListTransactionDetails(
|
||||||
|
startHeight, chainTip, "", 5, 0,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, txDetails, 0)
|
||||||
|
|
||||||
|
// Query for transactions, setting indexOffset to 4 (edge offset) and
|
||||||
|
// max_transactions to 0.
|
||||||
|
txDetails, _, _, err = alice.ListTransactionDetails(
|
||||||
|
startHeight, chainTip, "", 4, 0,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, txDetails, 1)
|
||||||
|
|
||||||
|
// Query for transactions, setting max_transactions to 0.
|
||||||
|
txDetails, _, _, err = alice.ListTransactionDetails(
|
||||||
|
startHeight, chainTip, "", 0, 0,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, txDetails, 5)
|
||||||
|
|
||||||
|
// Query for transactions, more than we have in the wallet (5).
|
||||||
|
txDetails, _, _, err = alice.ListTransactionDetails(
|
||||||
|
startHeight, chainTip, "", 0, 10,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, txDetails, 5)
|
||||||
|
|
||||||
|
// Query for transactions where the offset is greater than the number
|
||||||
|
// of transactions available.
|
||||||
|
txDetails, _, _, err = alice.ListTransactionDetails(
|
||||||
|
startHeight, chainTip, "", 10, 100,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, txDetails, 0)
|
||||||
|
}
|
||||||
|
|
||||||
func testTransactionSubscriptions(miner *rpctest.Harness,
|
func testTransactionSubscriptions(miner *rpctest.Harness,
|
||||||
alice, _ *lnwallet.LightningWallet, t *testing.T) {
|
alice, _ *lnwallet.LightningWallet, t *testing.T) {
|
||||||
|
|
||||||
@ -2812,6 +2919,10 @@ var walletTests = []walletTestCase{
|
|||||||
name: "transaction details",
|
name: "transaction details",
|
||||||
test: testListTransactionDetails,
|
test: testListTransactionDetails,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "transaction details offset",
|
||||||
|
test: testListTransactionDetailsOffset,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "get transaction details",
|
name: "get transaction details",
|
||||||
test: testGetTransactionDetails,
|
test: testGetTransactionDetails,
|
||||||
|
10
rpcserver.go
10
rpcserver.go
@ -6476,14 +6476,16 @@ func (r *rpcServer) GetTransactions(ctx context.Context,
|
|||||||
endHeight = req.EndHeight
|
endHeight = req.EndHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
transactions, err := r.server.cc.Wallet.ListTransactionDetails(
|
txns, firstIdx, lastIdx, err :=
|
||||||
req.StartHeight, endHeight, req.Account,
|
r.server.cc.Wallet.ListTransactionDetails(
|
||||||
)
|
req.StartHeight, endHeight, req.Account,
|
||||||
|
req.IndexOffset, req.MaxTransactions,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return lnrpc.RPCTransactionDetails(transactions), nil
|
return lnrpc.RPCTransactionDetails(txns, firstIdx, lastIdx), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DescribeGraph returns a description of the latest graph state from the PoV
|
// DescribeGraph returns a description of the latest graph state from the PoV
|
||||||
|
Loading…
x
Reference in New Issue
Block a user