feat(wallet) api to retrieve last activity timestamp

Also fix the lookup source for `GetRecipients` API

Updates status-desktop #11169
This commit is contained in:
Stefan 2023-06-21 10:01:31 +02:00 committed by Stefan Dunca
parent d3e650d5e5
commit ea7a389075
4 changed files with 147 additions and 19 deletions

View File

@ -364,7 +364,7 @@ const (
)
OR (filterActivityTypeReceive
AND (filterAllAddresses
OR (HEX(transfers.tx_to_address) IN filter_addresses))
OR (HEX(transfers.tx_to_address) IN filter_addresses))
)
)
AND (filterAllAddresses

View File

@ -3,6 +3,7 @@ package activity
import (
"context"
"database/sql"
"fmt"
eth "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
@ -91,28 +92,28 @@ type Filter struct {
// TODO: consider sorting by saved address and contacts to offload the client from doing it at runtime
func GetRecipients(ctx context.Context, db *sql.DB, offset int, limit int) (addresses []eth.Address, hasMore bool, err error) {
rows, err := db.QueryContext(ctx, `
SELECT
transfers.address as to_address,
transfers.timestamp AS timestamp
FROM transfers
WHERE transfers.multi_transaction_id = 0
SELECT
transfers.tx_to_address as to_address,
transfers.timestamp AS timestamp
FROM transfers
WHERE transfers.multi_transaction_id = 0
UNION ALL
UNION ALL
SELECT
pending_transactions.to_address AS to_address,
pending_transactions.timestamp AS timestamp
FROM pending_transactions
WHERE pending_transactions.multi_transaction_id = 0
SELECT
pending_transactions.to_address AS to_address,
pending_transactions.timestamp AS timestamp
FROM pending_transactions
WHERE pending_transactions.multi_transaction_id = 0
UNION ALL
UNION ALL
SELECT
multi_transactions.to_address AS to_address,
multi_transactions.timestamp AS timestamp
FROM multi_transactions
ORDER BY timestamp DESC
LIMIT ? OFFSET ?`, limit, offset)
SELECT
multi_transactions.to_address AS to_address,
multi_transactions.timestamp AS timestamp
FROM multi_transactions
ORDER BY timestamp DESC
LIMIT ? OFFSET ?`, limit, offset)
if err != nil {
return nil, false, err
}
@ -137,3 +138,60 @@ func GetRecipients(ctx context.Context, db *sql.DB, offset int, limit int) (addr
return entries, hasMore, nil
}
func GetOldestTimestamp(ctx context.Context, db *sql.DB, addresses []eth.Address) (timestamp int64, err error) {
queryFormatString := `
WITH filter_conditions AS (SELECT ? AS filterAllAddresses),
filter_addresses(address) AS (
SELECT * FROM (VALUES %s) WHERE (SELECT filterAllAddresses FROM filter_conditions) = 0
)
SELECT
transfers.tx_from_address AS from_address,
transfers.tx_to_address AS to_address,
transfers.timestamp AS timestamp
FROM transfers, filter_conditions
WHERE transfers.multi_transaction_id = 0
AND (filterAllAddresses OR HEX(from_address) IN filter_addresses OR HEX(to_address) IN filter_addresses)
UNION ALL
SELECT
pending_transactions.from_address AS from_address,
pending_transactions.to_address AS to_address,
pending_transactions.timestamp AS timestamp
FROM pending_transactions, filter_conditions
WHERE pending_transactions.multi_transaction_id = 0
AND (filterAllAddresses OR HEX(from_address) IN filter_addresses OR HEX(to_address) IN filter_addresses)
UNION ALL
SELECT
multi_transactions.from_address AS from_address,
multi_transactions.to_address AS to_address,
multi_transactions.timestamp AS timestamp
FROM multi_transactions, filter_conditions
WHERE filterAllAddresses OR HEX(from_address) IN filter_addresses OR HEX(to_address) IN filter_addresses
ORDER BY timestamp ASC
LIMIT 1`
filterAllAddresses := len(addresses) == 0
involvedAddresses := noEntriesInTmpTableSQLValues
if !filterAllAddresses {
involvedAddresses = joinAddresses(addresses)
}
queryString := fmt.Sprintf(queryFormatString, involvedAddresses)
row := db.QueryRowContext(ctx, queryString, filterAllAddresses)
var fromAddress, toAddress sql.NullString
err = row.Scan(&fromAddress, &toAddress, &timestamp)
if err == sql.ErrNoRows {
return 0, nil
}
if err != nil {
return 0, err
}
return timestamp, nil
}

View File

@ -6,7 +6,10 @@ import (
"fmt"
"testing"
eth "github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/appdatabase"
"github.com/status-im/status-go/services/wallet/testutils"
"github.com/status-im/status-go/services/wallet/transfer"
"github.com/stretchr/testify/require"
@ -61,3 +64,65 @@ func TestGetRecipients(t *testing.T) {
require.Equal(t, 4, len(entries))
require.True(t, hasMore)
}
func TestGetOldestTimestampEmptyDB(t *testing.T) {
db, close := setupTestFilterDB(t)
defer close()
timestamp, err := GetOldestTimestamp(context.Background(), db, []eth.Address{eth.HexToAddress("0x1")})
require.NoError(t, err)
require.Equal(t, int64(0), timestamp)
}
func TestGetOldestTimestamp(t *testing.T) {
db, close := setupTestFilterDB(t)
defer close()
// Add 6 extractable transactions
trs, _, _ := transfer.GenerateTestTransfers(t, db, 0, 7)
for i := range trs {
if i < 5 {
transfer.InsertTestTransfer(t, db, trs[i].To, &trs[i])
} else {
transfer.InsertTestPendingTransaction(t, db, &trs[i])
}
}
multiTxs := []transfer.TestMultiTransaction{
transfer.GenerateTestBridgeMultiTransaction(trs[0], trs[1]),
transfer.GenerateTestSwapMultiTransaction(trs[2], testutils.SntSymbol, 100),
}
// Extract oldest timestamp, no filter
timestamp, err := GetOldestTimestamp(context.Background(), db, []eth.Address{})
require.NoError(t, err)
require.Equal(t, multiTxs[0].Timestamp, timestamp)
// Test to filter
timestamp, err = GetOldestTimestamp(context.Background(), db, []eth.Address{
trs[3].To,
})
require.NoError(t, err)
require.Equal(t, trs[3].Timestamp, timestamp)
// Test from filter
timestamp, err = GetOldestTimestamp(context.Background(), db, []eth.Address{
trs[4].From,
})
require.NoError(t, err)
require.Equal(t, trs[4].Timestamp, timestamp)
// Test MT
timestamp, err = GetOldestTimestamp(context.Background(), db, []eth.Address{
multiTxs[1].FromAddress, trs[4].To,
})
require.NoError(t, err)
require.Equal(t, multiTxs[1].Timestamp, timestamp)
// Test Pending
timestamp, err = GetOldestTimestamp(context.Background(), db, []eth.Address{
trs[6].To,
})
require.NoError(t, err)
require.Equal(t, trs[6].Timestamp, timestamp)
}

View File

@ -551,3 +551,8 @@ func (api *API) GetAllRecipients(ctx context.Context, offset int, limit int) (re
result.Addresses, result.HasMore, err = activity.GetRecipients(ctx, api.s.db, offset, limit)
return result, err
}
func (api *API) GetOldestActivityTimestamp(ctx context.Context, addresses []common.Address) (timestamp int64, err error) {
log.Debug("wallet.api.GetOldestActivityTimestamp", "addresses.len", len(addresses))
return activity.GetOldestTimestamp(ctx, api.s.db, addresses)
}