Skip to content

Commit d7d8f9d

Browse files
authored
Merge pull request #1794 from lightninglabs/feat/filter-by-timestamp-addr-receives
Filter AddrReceives by timestamp
2 parents 0ddb086 + c0bcb10 commit d7d8f9d

File tree

12 files changed

+661
-441
lines changed

12 files changed

+661
-441
lines changed

address/event.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ type EventQueryParams struct {
6060
// (inclusive). Can be set to nil to return events of all creation
6161
// times.
6262
CreationTimeFrom *time.Time
63+
64+
// CreationTimeTo is the latest creation time to query for
65+
// (inclusive). Can be set to nil to return events of all creation
66+
// times.
67+
CreationTimeTo *time.Time
6368
}
6469

6570
// AssetOutput holds the information about a single asset output that was sent

cmd/commands/addrs.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,16 @@ var receivesAddrCommand = cli.Command{
283283
Name: addrName,
284284
Usage: "show transfers of a single address only",
285285
},
286+
cli.Uint64Flag{
287+
Name: "start_timestamp",
288+
Usage: "filter transfers created after this + " +
289+
"unix timestamp (seconds)",
290+
},
291+
cli.Uint64Flag{
292+
Name: "end_timestamp",
293+
Usage: "filter transfers created before this + " +
294+
"unix timestamp (seconds)",
295+
},
286296
},
287297
Action: addrReceives,
288298
}
@@ -302,7 +312,9 @@ func addrReceives(ctx *cli.Context) error {
302312
}
303313

304314
resp, err := client.AddrReceives(ctxc, &taprpc.AddrReceivesRequest{
305-
FilterAddr: addr,
315+
FilterAddr: addr,
316+
StartTimestamp: ctx.Uint64("start_timestamp"),
317+
EndTimestamp: ctx.Uint64("end_timestamp"),
306318
})
307319
if err != nil {
308320
return fmt.Errorf("unable to query addr receives: %w", err)

docs/release-notes/release-notes-0.7.0.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@
168168
user to specify a custom amount to send to a V2 address that doesn't have an
169169
amount specified.
170170

171+
- The `AddrReceives` RPC now supports timestamp filtering with
172+
[new `StartTimestamp` and `EndTimestamp` fields](https://github.com/lightninglabs/taproot-assets/pull/1794).
173+
171174
## tapcli Additions
172175

173176
- [Rename](https://github.com/lightninglabs/taproot-assets/pull/1682) the mint
@@ -186,6 +189,9 @@
186189
includes unset and zero-valued proto fields (e.g. transaction output indexes).
187190
This ensures consistent output shape across all proto messages.
188191

192+
- The `tapcli addrs receives` command now supports
193+
[new `--start_timestamp` and `--end_timestamp` flags](https://github.com/lightninglabs/taproot-assets/pull/1794).
194+
189195
# Improvements
190196

191197
## Functional Updates

itest/addrs_test.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,146 @@ func testUnknownTlvType(t *harnessTest) {
873873
require.False(t.t, verifyResp.Valid)
874874
}
875875

876+
// testAddrReceives tests the fetching of address events.
877+
func testAddrReceives(t *harnessTest) {
878+
// First, mint an asset so we have something to create addresses for.
879+
rpcAssets := MintAssetsConfirmBatch(
880+
t.t, t.lndHarness.Miner().Client, t.tapd,
881+
[]*mintrpc.MintAssetRequest{
882+
simpleAssets[0],
883+
},
884+
)
885+
asset := rpcAssets[0]
886+
887+
ctxb := context.Background()
888+
ctxt, cancel := context.WithTimeout(ctxb, defaultWaitTimeout)
889+
defer cancel()
890+
891+
// Create a second node that'll be the receiver.
892+
bobLnd := t.lndHarness.NewNodeWithCoins("Bob", nil)
893+
bob := setupTapdHarness(t.t, t, bobLnd, t.universeServer)
894+
defer func() {
895+
require.NoError(t.t, bob.stop(!*noDelete))
896+
}()
897+
898+
// Create an address and send assets to it.
899+
addr, events := NewAddrWithEventStream(
900+
t.t, bob, &taprpc.NewAddrRequest{
901+
AssetId: asset.AssetGenesis.AssetId,
902+
Amt: asset.Amount - 1,
903+
AssetVersion: asset.Version,
904+
},
905+
)
906+
907+
AssertAddrCreated(t.t, bob, asset, addr)
908+
909+
// Record the time before sending.
910+
timeBeforeSend := time.Now()
911+
912+
// Send assets to the address.
913+
sendResp, sendEvents := sendAssetsToAddr(t, t.tapd, addr)
914+
require.NotNil(t.t, sendResp)
915+
916+
// Wait for the event to be detected.
917+
AssertAddrEvent(t.t, bob, addr, 1, statusDetected)
918+
919+
// Mine a block to confirm the transaction.
920+
MineBlocks(t.t, t.lndHarness.Miner().Client, 1, 1)
921+
922+
// Wait for the event to be confirmed.
923+
AssertAddrEvent(t.t, bob, addr, 1, statusConfirmed)
924+
925+
// Record the time after sending.
926+
timeAfterSend := time.Now()
927+
928+
// Wait for the receive to complete.
929+
AssertNonInteractiveRecvComplete(t.t, bob, 1)
930+
AssertSendEventsComplete(t.t, addr.ScriptKey, sendEvents)
931+
AssertReceiveEvents(t.t, addr, events)
932+
933+
// Test 1: Get all events without timestamp filtering.
934+
resp, err := bob.AddrReceives(
935+
ctxt, &taprpc.AddrReceivesRequest{},
936+
)
937+
require.NoError(t.t, err)
938+
require.Len(t.t, resp.Events, 1)
939+
940+
// Test 2: Filter by start timestamp before the send
941+
// (should return events).
942+
resp, err = bob.AddrReceives(
943+
ctxt, &taprpc.AddrReceivesRequest{
944+
StartTimestamp: uint64(timeBeforeSend.Unix()),
945+
},
946+
)
947+
require.NoError(t.t, err)
948+
require.Len(t.t, resp.Events, 1)
949+
950+
// Test 3: Filter by start timestamp exactly at the send time
951+
// (should return the event).
952+
resp, err = bob.AddrReceives(
953+
ctxt, &taprpc.AddrReceivesRequest{
954+
StartTimestamp: uint64(timeBeforeSend.Unix()),
955+
},
956+
)
957+
require.NoError(t.t, err)
958+
require.Len(t.t, resp.Events, 1)
959+
960+
// Test 4: Filter by address and start timestamp.
961+
resp, err = bob.AddrReceives(
962+
ctxt, &taprpc.AddrReceivesRequest{
963+
FilterAddr: addr.Encoded,
964+
StartTimestamp: uint64(timeBeforeSend.Unix()),
965+
},
966+
)
967+
require.NoError(t.t, err)
968+
require.Len(t.t, resp.Events, 1)
969+
require.Equal(
970+
t.t, addr.Encoded, resp.Events[0].Addr.Encoded,
971+
)
972+
973+
// Test 5: Filter by address and start timestamp after send
974+
// (should return no events).
975+
resp, err = bob.AddrReceives(
976+
ctxt, &taprpc.AddrReceivesRequest{
977+
FilterAddr: addr.Encoded,
978+
StartTimestamp: uint64(timeAfterSend.Unix() + 1),
979+
},
980+
)
981+
require.NoError(t.t, err)
982+
require.Len(t.t, resp.Events, 0)
983+
984+
// Test 6: Filter by end timestamp before the send
985+
// (should return no events).
986+
resp, err = bob.AddrReceives(
987+
ctxt, &taprpc.AddrReceivesRequest{
988+
EndTimestamp: uint64(timeBeforeSend.Unix()),
989+
},
990+
)
991+
require.NoError(t.t, err)
992+
require.Len(t.t, resp.Events, 0)
993+
994+
// Test 7: Filter by end timestamp after the send
995+
// (should return the event).
996+
resp, err = bob.AddrReceives(
997+
ctxt, &taprpc.AddrReceivesRequest{
998+
EndTimestamp: uint64(timeAfterSend.Unix() + 1),
999+
},
1000+
)
1001+
require.NoError(t.t, err)
1002+
require.Len(t.t, resp.Events, 1)
1003+
1004+
// Test 8: Filter by both start and end timestamp
1005+
// (should return the event).
1006+
resp, err = bob.AddrReceives(
1007+
ctxt, &taprpc.AddrReceivesRequest{
1008+
StartTimestamp: uint64(timeBeforeSend.Unix()),
1009+
EndTimestamp: uint64(timeAfterSend.Unix() + 1),
1010+
},
1011+
)
1012+
require.NoError(t.t, err)
1013+
require.Len(t.t, resp.Events, 1)
1014+
}
1015+
8761016
// sendProof manually exports a proof from the given source node and imports it
8771017
// using the development only ImportProof RPC on the destination node.
8781018
func sendProof(t *harnessTest, src, dst *tapdHarness,

itest/test_list_on_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ var allTestCases = []*testCase{
5353
name: "addresses",
5454
test: testAddresses,
5555
},
56+
{
57+
name: "address receives",
58+
test: testAddrReceives,
59+
},
5660
{
5761
name: "multi address",
5862
test: testMultiAddress,

rpcserver.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2271,6 +2271,16 @@ func (r *rpcServer) AddrReceives(ctx context.Context,
22712271
sqlQuery.StatusTo = &status
22722272
}
22732273

2274+
// Add timestamp filtering if specified
2275+
if req.StartTimestamp > 0 {
2276+
startTime := time.Unix(int64(req.StartTimestamp), 0)
2277+
sqlQuery.CreationTimeFrom = &startTime
2278+
}
2279+
if req.EndTimestamp > 0 {
2280+
endTime := time.Unix(int64(req.EndTimestamp), 0)
2281+
sqlQuery.CreationTimeTo = &endTime
2282+
}
2283+
22742284
events, err := r.cfg.AddrBook.QueryEvents(ctx, sqlQuery)
22752285
if err != nil {
22762286
return nil, fmt.Errorf("error querying events: %w", err)
@@ -4154,12 +4164,6 @@ func (r *rpcServer) FetchSupplyCommit(ctx context.Context,
41544164
req *unirpc.FetchSupplyCommitRequest) (
41554165
*unirpc.FetchSupplyCommitResponse, error) {
41564166

4157-
// Check the rate limiter to see if we need to wait at all. If not then
4158-
// this'll be a noop.
4159-
if err := r.proofQueryRateLimiter.Wait(ctx); err != nil {
4160-
return nil, err
4161-
}
4162-
41634167
groupPubKey, err := unmarshalGroupKey(
41644168
req.GetGroupKeyBytes(), req.GetGroupKeyStr(),
41654169
)
@@ -4731,12 +4735,6 @@ func (r *rpcServer) InsertSupplyCommit(ctx context.Context,
47314735
req *unirpc.InsertSupplyCommitRequest) (
47324736
*unirpc.InsertSupplyCommitResponse, error) {
47334737

4734-
// Check the rate limiter to see if we need to wait at all. If not then
4735-
// this'll be a noop.
4736-
if err := r.proofQueryRateLimiter.Wait(ctx); err != nil {
4737-
return nil, err
4738-
}
4739-
47404738
groupPubKey, err := unmarshalGroupKey(
47414739
req.GetGroupKeyBytes(), req.GetGroupKeyStr(),
47424740
)

tapdb/addrs.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -990,9 +990,10 @@ func (t *TapAddressBook) QueryAddrEvents(
990990
error) {
991991

992992
sqlQuery := AddrEventQuery{
993-
StatusFrom: int16(address.StatusTransactionDetected),
994-
StatusTo: int16(address.StatusCompleted),
995-
CreatedAfter: time.Unix(0, 0).UTC(),
993+
StatusFrom: int16(address.StatusTransactionDetected),
994+
StatusTo: int16(address.StatusCompleted),
995+
CreatedAfter: time.Unix(0, 0).UTC(),
996+
CreatedBefore: time.Now().UTC(),
996997
}
997998
if len(params.AddrTaprootOutputKey) > 0 {
998999
sqlQuery.AddrTaprootKey = params.AddrTaprootOutputKey
@@ -1006,6 +1007,13 @@ func (t *TapAddressBook) QueryAddrEvents(
10061007
if params.CreationTimeFrom != nil && !params.CreationTimeFrom.IsZero() {
10071008
sqlQuery.CreatedAfter = params.CreationTimeFrom.UTC()
10081009
}
1010+
if params.CreationTimeTo != nil && !params.CreationTimeTo.IsZero() {
1011+
sqlQuery.CreatedBefore = params.CreationTimeTo.UTC()
1012+
}
1013+
if sqlQuery.CreatedAfter.After(sqlQuery.CreatedBefore) {
1014+
return nil, fmt.Errorf("created after time after " +
1015+
"created before time")
1016+
}
10091017

10101018
var (
10111019
readTxOpts = NewAssetStoreReadTx()

tapdb/sqlc/addrs.sql.go

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tapdb/sqlc/queries/addrs.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ WHERE addr_events.status >= @status_from
226226
AND addr_events.status <= @status_to
227227
AND COALESCE(@addr_taproot_key, addrs.taproot_output_key) = addrs.taproot_output_key
228228
AND addr_events.creation_time >= @created_after
229+
AND addr_events.creation_time <= @created_before
229230
ORDER by addr_events.creation_time;
230231

231232
-- name: QueryLastEventHeight :one

0 commit comments

Comments
 (0)