Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions address/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ type EventQueryParams struct {
// (inclusive). Can be set to nil to return events of all creation
// times.
CreationTimeFrom *time.Time

// CreationTimeTo is the latest creation time to query for
// (inclusive). Can be set to nil to return events of all creation
// times.
CreationTimeTo *time.Time
}

// AssetOutput holds the information about a single asset output that was sent
Expand Down
14 changes: 13 additions & 1 deletion cmd/commands/addrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,16 @@ var receivesAddrCommand = cli.Command{
Name: addrName,
Usage: "show transfers of a single address only",
},
cli.Uint64Flag{
Name: "start_timestamp",
Usage: "filter transfers created after this + " +
"unix timestamp (seconds)",
},
cli.Uint64Flag{
Name: "end_timestamp",
Usage: "filter transfers created before this + " +
"unix timestamp (seconds)",
},
},
Action: addrReceives,
}
Expand All @@ -302,7 +312,9 @@ func addrReceives(ctx *cli.Context) error {
}

resp, err := client.AddrReceives(ctxc, &taprpc.AddrReceivesRequest{
FilterAddr: addr,
FilterAddr: addr,
StartTimestamp: ctx.Uint64("start_timestamp"),
EndTimestamp: ctx.Uint64("end_timestamp"),
})
if err != nil {
return fmt.Errorf("unable to query addr receives: %w", err)
Expand Down
65 changes: 65 additions & 0 deletions docs/release-notes/release-notes-0.8.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Release Notes
- [Bug Fixes](#bug-fixes)
- [New Features](#new-features)
- [Functional Enhancements](#functional-enhancements)
- [RPC Additions](#rpc-additions)
- [tapcli Additions](#tapcli-additions)
- [Improvements](#improvements)
- [Functional Updates](#functional-updates)
- [RPC Updates](#rpc-updates)
- [tapcli Updates](#tapcli-updates)
- [Breaking Changes](#breaking-changes)
- [Performance Improvements](#performance-improvements)
- [Deprecations](#deprecations)
- [Technical and Architectural Updates](#technical-and-architectural-updates)
- [BIP/bLIP Spec Updates](#bipblip-spec-updates)
- [Testing](#testing)
- [Database](#database)
- [Code Health](#code-health)
- [Tooling and Documentation](#tooling-and-documentation)

# Bug Fixes

# New Features

## Functional Enhancements

## RPC Additions

- The `AddrReceives` RPC now supports timestamp filtering with
[new `start_timestamp` and `end_timestamp` fields](https://github.com/lightninglabs/taproot-assets/pull/1794).

## tapcli Additions

- The `tapcli addrs receives` command now supports
[new `--start_timestamp` and `--end_timestamp` flags](https://github.com/lightninglabs/taproot-assets/pull/1794).

# Improvements

## Functional Updates

## RPC Updates

## tapcli Updates

## Code Health

## Breaking Changes

## Performance Improvements

## Deprecations

# Technical and Architectural Updates

## BIP/bLIP Spec Updates

## Testing

## Database

## Code Health

## Tooling and Documentation

# Contributors (Alphabetical Order)
150 changes: 150 additions & 0 deletions itest/addrs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,156 @@ func testUnknownTlvType(t *harnessTest) {
require.False(t.t, verifyResp.Valid)
}

// testAddrReceivestests tests AddrReceives and its filters.
func testAddrReceives(t *harnessTest) {
// First, mint an asset so we have something to create addresses for.
rpcAssets := MintAssetsConfirmBatch(
t.t, t.lndHarness.Miner().Client, t.tapd,
[]*mintrpc.MintAssetRequest{
simpleAssets[0],
},
)
asset := rpcAssets[0]

ctxb := context.Background()
ctxt, cancel := context.WithTimeout(ctxb, defaultWaitTimeout)
defer cancel()

// Create a second node that'll be the receiver.
bobLnd := t.lndHarness.NewNodeWithCoins("Bob", nil)
bob := setupTapdHarness(t.t, t, bobLnd, t.universeServer)
defer func() {
require.NoError(t.t, bob.stop(!*noDelete))
}()

// Create an address and send assets to it.
addr, events := NewAddrWithEventStream(
t.t, bob, &taprpc.NewAddrRequest{
AssetId: asset.AssetGenesis.AssetId,
Amt: asset.Amount - 1,
AssetVersion: asset.Version,
},
)

AssertAddrCreated(t.t, bob, asset, addr)

// Record the time before sending
timeBeforeSend := time.Now()

// Send assets to the address
sendResp, sendEvents := sendAssetsToAddr(t, t.tapd, addr)
require.NotNil(t.t, sendResp)

// Wait for the event to be detected
AssertAddrEvent(t.t, bob, addr, 1, statusDetected)

// Mine a block to confirm the transaction
MineBlocks(t.t, t.lndHarness.Miner().Client, 1, 1)

// Wait for the event to be confirmed
AssertAddrEvent(t.t, bob, addr, 1, statusConfirmed)

// Record the time after sending
timeAfterSend := time.Now()

// Wait for the receive to complete
AssertNonInteractiveRecvComplete(t.t, bob, 1)
AssertSendEventsComplete(t.t, addr.ScriptKey, sendEvents)
AssertReceiveEvents(t.t, addr, events)

// Test 1: Get all events without timestamp filtering
resp, err := bob.AddrReceives(
ctxt, &taprpc.AddrReceivesRequest{},
)
require.NoError(t.t, err)
require.Len(t.t, resp.Events, 1)

// Test 2: Filter by start timestamp before the send
// (should return events)
resp, err = bob.AddrReceives(
ctxt, &taprpc.AddrReceivesRequest{
StartTimestamp: uint64(timeBeforeSend.Unix()),
},
)
require.NoError(t.t, err)
require.Len(t.t, resp.Events, 1)

// Test 3: Filter by start timestamp after the send
// (should return no events)
resp, err = bob.AddrReceives(
ctxt, &taprpc.AddrReceivesRequest{
StartTimestamp: uint64(timeAfterSend.Unix() + 1),
},
)
require.NoError(t.t, err)
require.Len(t.t, resp.Events, 0)

// Test 4: Filter by start timestamp exactly at the send time
// (should return the event)
resp, err = bob.AddrReceives(
ctxt, &taprpc.AddrReceivesRequest{
StartTimestamp: uint64(timeBeforeSend.Unix()),
},
)
require.NoError(t.t, err)
require.Len(t.t, resp.Events, 1)

// Test 5: Filter by address and start timestamp
resp, err = bob.AddrReceives(
ctxt, &taprpc.AddrReceivesRequest{
FilterAddr: addr.Encoded,
StartTimestamp: uint64(timeBeforeSend.Unix()),
},
)
require.NoError(t.t, err)
require.Len(t.t, resp.Events, 1)
require.Equal(
t.t, addr.Encoded, resp.Events[0].Addr.Encoded,
)

// Test 6: Filter by address and start timestamp after send
// (should return no events)
resp, err = bob.AddrReceives(
ctxt, &taprpc.AddrReceivesRequest{
FilterAddr: addr.Encoded,
StartTimestamp: uint64(timeAfterSend.Unix() + 1),
},
)
require.NoError(t.t, err)
require.Len(t.t, resp.Events, 0)

// Test 7: Filter by end timestamp before the send
// (should return no events)
resp, err = bob.AddrReceives(
ctxt, &taprpc.AddrReceivesRequest{
EndTimestamp: uint64(timeBeforeSend.Unix()),
},
)
require.NoError(t.t, err)
require.Len(t.t, resp.Events, 0)

// Test 8: Filter by end timestamp after the send
// (should return the event)
resp, err = bob.AddrReceives(
ctxt, &taprpc.AddrReceivesRequest{
EndTimestamp: uint64(timeAfterSend.Unix() + 1),
},
)
require.NoError(t.t, err)
require.Len(t.t, resp.Events, 1)

// Test 9: Filter by both start and end timestamp
// (should return the event)
resp, err = bob.AddrReceives(
ctxt, &taprpc.AddrReceivesRequest{
StartTimestamp: uint64(timeBeforeSend.Unix()),
EndTimestamp: uint64(timeAfterSend.Unix() + 1),
},
)
require.NoError(t.t, err)
require.Len(t.t, resp.Events, 1)
}

// sendProof manually exports a proof from the given source node and imports it
// using the development only ImportProof RPC on the destination node.
func sendProof(t *harnessTest, src, dst *tapdHarness,
Expand Down
4 changes: 4 additions & 0 deletions itest/test_list_on_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ var allTestCases = []*testCase{
name: "addresses",
test: testAddresses,
},
{
name: "addr receives",
test: testAddrReceives,
},
{
name: "multi address",
test: testMultiAddress,
Expand Down
22 changes: 10 additions & 12 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2271,6 +2271,16 @@ func (r *rpcServer) AddrReceives(ctx context.Context,
sqlQuery.StatusTo = &status
}

// Add timestamp filtering if specified
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth verifying that StartTimestamp < EndTimestamp here?

if req.StartTimestamp > 0 {
startTime := time.Unix(int64(req.StartTimestamp), 0)
sqlQuery.CreationTimeFrom = &startTime
}
if req.EndTimestamp > 0 {
endTime := time.Unix(int64(req.EndTimestamp), 0)
sqlQuery.CreationTimeTo = &endTime
}

events, err := r.cfg.AddrBook.QueryEvents(ctx, sqlQuery)
if err != nil {
return nil, fmt.Errorf("error querying events: %w", err)
Expand Down Expand Up @@ -4223,12 +4233,6 @@ func (r *rpcServer) FetchSupplyCommit(ctx context.Context,
req *unirpc.FetchSupplyCommitRequest) (
*unirpc.FetchSupplyCommitResponse, error) {

// Check the rate limiter to see if we need to wait at all. If not then
// this'll be a noop.
if err := r.proofQueryRateLimiter.Wait(ctx); err != nil {
return nil, err
}

groupPubKey, err := unmarshalGroupKey(
req.GetGroupKeyBytes(), req.GetGroupKeyStr(),
)
Expand Down Expand Up @@ -4800,12 +4804,6 @@ func (r *rpcServer) InsertSupplyCommit(ctx context.Context,
req *unirpc.InsertSupplyCommitRequest) (
*unirpc.InsertSupplyCommitResponse, error) {

// Check the rate limiter to see if we need to wait at all. If not then
// this'll be a noop.
if err := r.proofQueryRateLimiter.Wait(ctx); err != nil {
return nil, err
}

groupPubKey, err := unmarshalGroupKey(
req.GetGroupKeyBytes(), req.GetGroupKeyStr(),
)
Expand Down
10 changes: 7 additions & 3 deletions tapdb/addrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -990,9 +990,10 @@ func (t *TapAddressBook) QueryAddrEvents(
error) {

sqlQuery := AddrEventQuery{
StatusFrom: int16(address.StatusTransactionDetected),
StatusTo: int16(address.StatusCompleted),
CreatedAfter: time.Unix(0, 0).UTC(),
StatusFrom: int16(address.StatusTransactionDetected),
StatusTo: int16(address.StatusCompleted),
CreatedAfter: time.Unix(0, 0).UTC(),
CreatedBefore: time.Now().UTC(),
}
if len(params.AddrTaprootOutputKey) > 0 {
sqlQuery.AddrTaprootKey = params.AddrTaprootOutputKey
Expand All @@ -1006,6 +1007,9 @@ func (t *TapAddressBook) QueryAddrEvents(
if params.CreationTimeFrom != nil && !params.CreationTimeFrom.IsZero() {
sqlQuery.CreatedAfter = params.CreationTimeFrom.UTC()
}
if params.CreationTimeTo != nil && !params.CreationTimeTo.IsZero() {
sqlQuery.CreatedBefore = params.CreationTimeTo.UTC()
}

var (
readTxOpts = NewAssetStoreReadTx()
Expand Down
3 changes: 3 additions & 0 deletions tapdb/sqlc/addrs.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tapdb/sqlc/queries/addrs.sql
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ WHERE addr_events.status >= @status_from
AND addr_events.status <= @status_to
AND COALESCE(@addr_taproot_key, addrs.taproot_output_key) = addrs.taproot_output_key
AND addr_events.creation_time >= @created_after
AND addr_events.creation_time <= @created_before
ORDER by addr_events.creation_time;

-- name: QueryLastEventHeight :one
Expand Down
Loading