chore(wallet) remove activity filter dependency on accounts
Require that the activity filter is passed at least one account address to extract type sent/received Updates status-desktop #11980
This commit is contained in:
parent
494c6707ba
commit
ad971278d9
|
@ -1,15 +0,0 @@
|
||||||
package accounts
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MockTestAccounts(tb testing.TB, d *Database, accounts []*Account) {
|
|
||||||
err := d.SaveOrUpdateAccounts(accounts, false)
|
|
||||||
require.NoError(tb, err)
|
|
||||||
res, err := d.GetActiveAccounts()
|
|
||||||
require.NoError(tb, err)
|
|
||||||
require.Equal(tb, accounts[0].Address, res[0].Address)
|
|
||||||
}
|
|
|
@ -18,7 +18,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
||||||
"github.com/status-im/status-go/multiaccounts/accounts"
|
|
||||||
"github.com/status-im/status-go/services/wallet/bigint"
|
"github.com/status-im/status-go/services/wallet/bigint"
|
||||||
"github.com/status-im/status-go/services/wallet/common"
|
"github.com/status-im/status-go/services/wallet/common"
|
||||||
"github.com/status-im/status-go/services/wallet/thirdparty"
|
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||||
|
@ -37,8 +36,6 @@ const (
|
||||||
PendingTransactionPT
|
PendingTransactionPT
|
||||||
)
|
)
|
||||||
|
|
||||||
const keypairAccountsTable = "keypairs_accounts"
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ZeroAddress = eth.Address{}
|
ZeroAddress = eth.Address{}
|
||||||
)
|
)
|
||||||
|
@ -322,8 +319,7 @@ const (
|
||||||
var queryFormatString string
|
var queryFormatString string
|
||||||
|
|
||||||
type FilterDependencies struct {
|
type FilterDependencies struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
accountsDb *accounts.Database
|
|
||||||
// use token.TokenType, token.ChainID and token.Address to find the available symbol
|
// use token.TokenType, token.ChainID and token.Address to find the available symbol
|
||||||
tokenSymbol func(token Token) string
|
tokenSymbol func(token Token) string
|
||||||
// use the chainID and symbol to look up token.TokenType and token.Address. Return nil if not found
|
// use the chainID and symbol to look up token.TokenType and token.Address. Return nil if not found
|
||||||
|
@ -333,10 +329,18 @@ type FilterDependencies struct {
|
||||||
// getActivityEntries queries the transfers, pending_transactions, and multi_transactions tables based on filter parameters and arguments
|
// getActivityEntries queries the transfers, pending_transactions, and multi_transactions tables based on filter parameters and arguments
|
||||||
// it returns metadata for all entries ordered by timestamp column
|
// it returns metadata for all entries ordered by timestamp column
|
||||||
//
|
//
|
||||||
|
// addresses are mandatory and used to detect activity types SendAT and ReceiveAT for transfers entries
|
||||||
|
//
|
||||||
|
// allAddresses optimization indicates if the passed addresses include all the owners in the wallet DB
|
||||||
|
//
|
||||||
// Adding a no-limit option was never considered or required.
|
// Adding a no-limit option was never considered or required.
|
||||||
//
|
//
|
||||||
// TODO: optimization: consider implementing nullable []byte instead of using strings for addresses or insert binary (X'...' syntax) directly into the query
|
// TODO: optimization: consider implementing nullable []byte instead of using strings for addresses or insert binary (X'...' syntax) directly into the query
|
||||||
func getActivityEntries(ctx context.Context, deps FilterDependencies, addresses []eth.Address, chainIDs []common.ChainID, filter Filter, offset int, limit int) ([]Entry, error) {
|
func getActivityEntries(ctx context.Context, deps FilterDependencies, addresses []eth.Address, allAddresses bool, chainIDs []common.ChainID, filter Filter, offset int, limit int) ([]Entry, error) {
|
||||||
|
if len(addresses) == 0 {
|
||||||
|
return nil, errors.New("no addresses provided")
|
||||||
|
}
|
||||||
|
|
||||||
includeAllTokenTypeAssets := len(filter.Assets) == 0 && !filter.FilterOutAssets
|
includeAllTokenTypeAssets := len(filter.Assets) == 0 && !filter.FilterOutAssets
|
||||||
|
|
||||||
// Used for symbol bearing tables multi_transactions and pending_transactions
|
// Used for symbol bearing tables multi_transactions and pending_transactions
|
||||||
|
@ -378,7 +382,6 @@ func getActivityEntries(ctx context.Context, deps FilterDependencies, addresses
|
||||||
startFilterDisabled := !(filter.Period.StartTimestamp > 0)
|
startFilterDisabled := !(filter.Period.StartTimestamp > 0)
|
||||||
endFilterDisabled := !(filter.Period.EndTimestamp > 0)
|
endFilterDisabled := !(filter.Period.EndTimestamp > 0)
|
||||||
filterActivityTypeAll := len(filter.Types) == 0
|
filterActivityTypeAll := len(filter.Types) == 0
|
||||||
filterAllAddresses := len(addresses) == 0
|
|
||||||
filterAllToAddresses := len(filter.CounterpartyAddresses) == 0
|
filterAllToAddresses := len(filter.CounterpartyAddresses) == 0
|
||||||
includeAllStatuses := len(filter.Statuses) == 0
|
includeAllStatuses := len(filter.Statuses) == 0
|
||||||
|
|
||||||
|
@ -393,10 +396,7 @@ func getActivityEntries(ctx context.Context, deps FilterDependencies, addresses
|
||||||
filterStatusFinalized = sliceContains(filter.Statuses, FinalizedAS)
|
filterStatusFinalized = sliceContains(filter.Statuses, FinalizedAS)
|
||||||
}
|
}
|
||||||
|
|
||||||
involvedAddresses := noEntriesInTmpTableSQLValues
|
involvedAddresses := joinAddresses(addresses)
|
||||||
if !filterAllAddresses {
|
|
||||||
involvedAddresses = joinAddresses(addresses)
|
|
||||||
}
|
|
||||||
toAddresses := noEntriesInTmpTableSQLValues
|
toAddresses := noEntriesInTmpTableSQLValues
|
||||||
if !filterAllToAddresses {
|
if !filterAllToAddresses {
|
||||||
toAddresses = joinAddresses(filter.CounterpartyAddresses)
|
toAddresses = joinAddresses(filter.CounterpartyAddresses)
|
||||||
|
@ -407,23 +407,24 @@ func getActivityEntries(ctx context.Context, deps FilterDependencies, addresses
|
||||||
return strconv.Itoa(int(t))
|
return strconv.Itoa(int(t))
|
||||||
})
|
})
|
||||||
|
|
||||||
// Since the filter query needs addresses which are in a different database, we need to update the
|
queryString := fmt.Sprintf(queryFormatString, involvedAddresses, toAddresses, assetsTokenCodes, assetsERC20, networks,
|
||||||
// keypairs_accounts table in the current database with the latest addresses from the accounts database
|
joinedMTTypes)
|
||||||
err := updateKeypairsAccountsTable(deps.accountsDb, deps.db)
|
|
||||||
|
// The duplicated temporary table UNION with CTE acts as an optimization
|
||||||
|
// As soon as we use filter_addresses CTE or filter_addresses_table temp table
|
||||||
|
// or switch them alternatively for JOIN or IN clauses the performance drops significantly
|
||||||
|
_, err := deps.db.Exec(fmt.Sprintf("DROP TABLE IF EXISTS filter_addresses_table; CREATE TEMP TABLE filter_addresses_table (address VARCHAR PRIMARY KEY); INSERT OR IGNORE INTO filter_addresses_table (address) VALUES %s;\n", involvedAddresses))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
queryString := fmt.Sprintf(queryFormatString, keypairAccountsTable, involvedAddresses, toAddresses, assetsTokenCodes, assetsERC20, networks,
|
|
||||||
joinedMTTypes)
|
|
||||||
|
|
||||||
rows, err := deps.db.QueryContext(ctx, queryString,
|
rows, err := deps.db.QueryContext(ctx, queryString,
|
||||||
startFilterDisabled, filter.Period.StartTimestamp, endFilterDisabled, filter.Period.EndTimestamp,
|
startFilterDisabled, filter.Period.StartTimestamp, endFilterDisabled, filter.Period.EndTimestamp,
|
||||||
filterActivityTypeAll, sliceContains(filter.Types, SendAT), sliceContains(filter.Types, ReceiveAT),
|
filterActivityTypeAll, sliceContains(filter.Types, SendAT), sliceContains(filter.Types, ReceiveAT),
|
||||||
sliceContains(filter.Types, ContractDeploymentAT), sliceContains(filter.Types, MintAT),
|
sliceContains(filter.Types, ContractDeploymentAT), sliceContains(filter.Types, MintAT),
|
||||||
transfer.MultiTransactionSend,
|
transfer.MultiTransactionSend,
|
||||||
fromTrType, toTrType,
|
fromTrType, toTrType,
|
||||||
filterAllAddresses, filterAllToAddresses,
|
allAddresses, filterAllToAddresses,
|
||||||
includeAllStatuses, filterStatusCompleted, filterStatusFailed, filterStatusFinalized, filterStatusPending,
|
includeAllStatuses, filterStatusCompleted, filterStatusFailed, filterStatusFinalized, filterStatusPending,
|
||||||
FailedAS, CompleteAS, PendingAS,
|
FailedAS, CompleteAS, PendingAS,
|
||||||
includeAllTokenTypeAssets,
|
includeAllTokenTypeAssets,
|
||||||
|
@ -689,48 +690,6 @@ func contractTypeFromDBType(dbType string) (transferType *TransferType) {
|
||||||
return transferType
|
return transferType
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateKeypairsAccountsTable(accountsDb *accounts.Database, db *sql.DB) error {
|
|
||||||
_, err := db.Exec(fmt.Sprintf("CREATE TEMP TABLE IF NOT EXISTS %s (address VARCHAR PRIMARY KEY)",
|
|
||||||
keypairAccountsTable))
|
|
||||||
if err != nil {
|
|
||||||
log.Error("failed to create 'keypairs_accounts' table", "err", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: remove dependency on accounts table by removing"all accounts filter" optimization; see #11980
|
|
||||||
if accountsDb == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
addresses, err := accountsDb.GetWalletAddresses()
|
|
||||||
if err != nil {
|
|
||||||
log.Error("failed to get wallet addresses", "err", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tx, err := db.Begin()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err == nil {
|
|
||||||
err = tx.Commit()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_ = tx.Rollback()
|
|
||||||
}()
|
|
||||||
|
|
||||||
for _, address := range addresses {
|
|
||||||
_, err = tx.Exec(fmt.Sprintf("INSERT OR IGNORE INTO %s (address) VALUES (?)", keypairAccountsTable), address)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("failed to insert wallet addresses", "err", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// lookupAndFillInTokens ignores NFTs
|
// lookupAndFillInTokens ignores NFTs
|
||||||
func lookupAndFillInTokens(deps FilterDependencies, tokenOut *Token, tokenIn *Token) (symbolOut *string, symbolIn *string) {
|
func lookupAndFillInTokens(deps FilterDependencies, tokenOut *Token, tokenIn *Token) (symbolOut *string, symbolIn *string) {
|
||||||
if tokenOut != nil && tokenOut.TokenID == nil {
|
if tokenOut != nil && tokenOut.TokenID == nil {
|
||||||
|
|
|
@ -3,13 +3,9 @@ package activity
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/status-im/status-go/appdatabase"
|
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
|
||||||
"github.com/status-im/status-go/multiaccounts/accounts"
|
|
||||||
"github.com/status-im/status-go/services/wallet/common"
|
"github.com/status-im/status-go/services/wallet/common"
|
||||||
"github.com/status-im/status-go/services/wallet/testutils"
|
"github.com/status-im/status-go/services/wallet/testutils"
|
||||||
"github.com/status-im/status-go/services/wallet/transfer"
|
"github.com/status-im/status-go/services/wallet/transfer"
|
||||||
|
@ -40,28 +36,20 @@ func tokenFromSymbol(chainID *common.ChainID, symbol string) *Token {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupTestActivityDBStorageChoice(tb testing.TB, inMemory bool) (deps FilterDependencies, close func()) {
|
func setupTestActivityDBStorageChoice(tb testing.TB, inMemory bool) (deps FilterDependencies, close func()) {
|
||||||
var db, appDb *sql.DB
|
var db *sql.DB
|
||||||
var err error
|
var err error
|
||||||
cleanupDB := func() error { return nil }
|
cleanupDB := func() error { return nil }
|
||||||
cleanupWalletDB := func() error { return nil }
|
cleanupWalletDB := func() error { return nil }
|
||||||
if inMemory {
|
if inMemory {
|
||||||
db, err = helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
db, err = helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
||||||
require.NoError(tb, err)
|
require.NoError(tb, err)
|
||||||
appDb, err = helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{})
|
|
||||||
require.NoError(tb, err)
|
|
||||||
} else {
|
} else {
|
||||||
db, cleanupWalletDB, err = helpers.SetupTestSQLDB(walletdatabase.DbInitializer{}, "wallet-activity-tests")
|
db, cleanupWalletDB, err = helpers.SetupTestSQLDB(walletdatabase.DbInitializer{}, "wallet-activity-tests")
|
||||||
require.NoError(tb, err)
|
require.NoError(tb, err)
|
||||||
appDb, cleanupDB, err = helpers.SetupTestSQLDB(appdatabase.DbInitializer{}, "wallet-activity-tests")
|
|
||||||
require.NoError(tb, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
accountsDb, err := accounts.NewDB(appDb)
|
|
||||||
require.NoError(tb, err)
|
|
||||||
|
|
||||||
deps = FilterDependencies{
|
deps = FilterDependencies{
|
||||||
db: db,
|
db: db,
|
||||||
accountsDb: accountsDb,
|
|
||||||
tokenSymbol: func(token Token) string {
|
tokenSymbol: func(token Token) string {
|
||||||
switch token.TokenType {
|
switch token.TokenType {
|
||||||
case Native:
|
case Native:
|
||||||
|
@ -112,17 +100,6 @@ type testData struct {
|
||||||
nextIndex int
|
nextIndex int
|
||||||
}
|
}
|
||||||
|
|
||||||
func mockTestAccountsWithAddresses(tb testing.TB, db *accounts.Database, addresses []eth.Address) {
|
|
||||||
mockedAccounts := []*accounts.Account{}
|
|
||||||
for _, address := range addresses {
|
|
||||||
mockedAccounts = append(mockedAccounts, &accounts.Account{
|
|
||||||
Address: types.Address(address),
|
|
||||||
Type: accounts.AccountTypeWatch,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
accounts.MockTestAccounts(tb, db, mockedAccounts)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates and adds to the DB 7 transfers and 2 multitransactions.
|
// Generates and adds to the DB 7 transfers and 2 multitransactions.
|
||||||
// There are only 4 extractable activity entries (transactions + multi-transactions) with timestamps 1-4. The others are associated with a multi-transaction
|
// There are only 4 extractable activity entries (transactions + multi-transactions) with timestamps 1-4. The others are associated with a multi-transaction
|
||||||
func fillTestData(t *testing.T, db *sql.DB) (td testData, fromAddresses, toAddresses []eth.Address) {
|
func fillTestData(t *testing.T, db *sql.DB) (td testData, fromAddresses, toAddresses []eth.Address) {
|
||||||
|
@ -203,7 +180,7 @@ func TestGetActivityEntriesAll(t *testing.T) {
|
||||||
td, fromAddresses, toAddresses := fillTestData(t, deps.db)
|
td, fromAddresses, toAddresses := fillTestData(t, deps.db)
|
||||||
|
|
||||||
var filter Filter
|
var filter Filter
|
||||||
entries, err := getActivityEntries(context.Background(), deps, append(toAddresses, fromAddresses...), []common.ChainID{}, filter, 0, 10)
|
entries, err := getActivityEntries(context.Background(), deps, append(toAddresses, fromAddresses...), true, []common.ChainID{}, filter, 0, 10)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 4, len(entries))
|
require.Equal(t, 4, len(entries))
|
||||||
|
|
||||||
|
@ -295,9 +272,7 @@ func TestGetActivityEntriesWithSameTransactionForSenderAndReceiverInDB(t *testin
|
||||||
defer close()
|
defer close()
|
||||||
|
|
||||||
// Add 4 extractable transactions with timestamps 1-4
|
// Add 4 extractable transactions with timestamps 1-4
|
||||||
td, fromAddresses, toAddresses := fillTestData(t, deps.db)
|
td, _, _ := fillTestData(t, deps.db)
|
||||||
|
|
||||||
mockTestAccountsWithAddresses(t, deps.accountsDb, append(fromAddresses, toAddresses...))
|
|
||||||
|
|
||||||
// Add another transaction with owner reversed
|
// Add another transaction with owner reversed
|
||||||
senderTr := td.tr1
|
senderTr := td.tr1
|
||||||
|
@ -307,7 +282,7 @@ func TestGetActivityEntriesWithSameTransactionForSenderAndReceiverInDB(t *testin
|
||||||
transfer.InsertTestTransfer(t, deps.db, senderTr.From, &senderTr)
|
transfer.InsertTestTransfer(t, deps.db, senderTr.From, &senderTr)
|
||||||
|
|
||||||
var filter Filter
|
var filter Filter
|
||||||
entries, err := getActivityEntries(context.Background(), deps, []eth.Address{td.tr1.To, senderTr.From}, []common.ChainID{}, filter, 0, 10)
|
entries, err := getActivityEntries(context.Background(), deps, []eth.Address{td.tr1.To, senderTr.From}, false, []common.ChainID{}, filter, 0, 10)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 2, len(entries))
|
require.Equal(t, 2, len(entries))
|
||||||
|
|
||||||
|
@ -335,13 +310,13 @@ func TestGetActivityEntriesFilterByTime(t *testing.T) {
|
||||||
transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
|
transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
mockTestAccountsWithAddresses(t, deps.accountsDb, append(append(append(fromTds, toTds...), fromTrs...), toTrs...))
|
allAddresses := append(append(append(fromTds, toTds...), fromTrs...), toTrs...)
|
||||||
|
|
||||||
// Test start only
|
// Test start only
|
||||||
var filter Filter
|
var filter Filter
|
||||||
filter.Period.StartTimestamp = td.multiTx1.Timestamp
|
filter.Period.StartTimestamp = td.multiTx1.Timestamp
|
||||||
filter.Period.EndTimestamp = NoLimitTimestampForPeriod
|
filter.Period.EndTimestamp = NoLimitTimestampForPeriod
|
||||||
entries, err := getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 8, len(entries))
|
require.Equal(t, 8, len(entries))
|
||||||
|
|
||||||
|
@ -387,7 +362,7 @@ func TestGetActivityEntriesFilterByTime(t *testing.T) {
|
||||||
|
|
||||||
// Test complete interval
|
// Test complete interval
|
||||||
filter.Period.EndTimestamp = trs[2].Timestamp
|
filter.Period.EndTimestamp = trs[2].Timestamp
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 5, len(entries))
|
require.Equal(t, 5, len(entries))
|
||||||
|
|
||||||
|
@ -433,7 +408,7 @@ func TestGetActivityEntriesFilterByTime(t *testing.T) {
|
||||||
|
|
||||||
// Test end only
|
// Test end only
|
||||||
filter.Period.StartTimestamp = NoLimitTimestampForPeriod
|
filter.Period.StartTimestamp = NoLimitTimestampForPeriod
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 7, len(entries))
|
require.Equal(t, 7, len(entries))
|
||||||
// Check start and end content
|
// Check start and end content
|
||||||
|
@ -487,18 +462,18 @@ func TestGetActivityEntriesCheckOffsetAndLimit(t *testing.T) {
|
||||||
transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
|
transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
mockTestAccountsWithAddresses(t, deps.accountsDb, append(fromTrs, toTrs...))
|
allAddresses := append(fromTrs, toTrs...)
|
||||||
|
|
||||||
var filter Filter
|
var filter Filter
|
||||||
// Get all
|
// Get all
|
||||||
entries, err := getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 5)
|
entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 5)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 5, len(entries))
|
require.Equal(t, 5, len(entries))
|
||||||
|
|
||||||
// Get time based interval
|
// Get time based interval
|
||||||
filter.Period.StartTimestamp = trs[2].Timestamp
|
filter.Period.StartTimestamp = trs[2].Timestamp
|
||||||
filter.Period.EndTimestamp = trs[8].Timestamp
|
filter.Period.EndTimestamp = trs[8].Timestamp
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 3)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 3)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 3, len(entries))
|
require.Equal(t, 3, len(entries))
|
||||||
// Check start and end content
|
// Check start and end content
|
||||||
|
@ -542,7 +517,7 @@ func TestGetActivityEntriesCheckOffsetAndLimit(t *testing.T) {
|
||||||
}, entries[2])
|
}, entries[2])
|
||||||
|
|
||||||
// Move window 2 entries forward
|
// Move window 2 entries forward
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 2, 3)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 2, 3)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 3, len(entries))
|
require.Equal(t, 3, len(entries))
|
||||||
// Check start and end content
|
// Check start and end content
|
||||||
|
@ -586,7 +561,7 @@ func TestGetActivityEntriesCheckOffsetAndLimit(t *testing.T) {
|
||||||
}, entries[2])
|
}, entries[2])
|
||||||
|
|
||||||
// Move window 4 more entries to test filter cap
|
// Move window 4 more entries to test filter cap
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 6, 3)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 6, 3)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 1, len(entries))
|
require.Equal(t, 1, len(entries))
|
||||||
// Check start and end content
|
// Check start and end content
|
||||||
|
@ -638,16 +613,18 @@ func TestGetActivityEntriesFilterByType(t *testing.T) {
|
||||||
defer close()
|
defer close()
|
||||||
|
|
||||||
// Adds 4 extractable transactions
|
// Adds 4 extractable transactions
|
||||||
td, _, _ := fillTestData(t, deps.db)
|
td, tdFromAdds, tdToAddrs := fillTestData(t, deps.db)
|
||||||
// Add 5 extractable transactions: one MultiTransactionSwap, two MultiTransactionBridge and two MultiTransactionSend
|
// Add 5 extractable transactions: one MultiTransactionSwap, two MultiTransactionBridge and two MultiTransactionSend
|
||||||
multiTxs := make([]transfer.TestMultiTransaction, 5)
|
multiTxs := make([]transfer.TestMultiTransaction, 5)
|
||||||
trs, _, _ := transfer.GenerateTestTransfers(t, deps.db, td.nextIndex, len(multiTxs)*2)
|
trs, fromAddrs, toAddrs := transfer.GenerateTestTransfers(t, deps.db, td.nextIndex, len(multiTxs)*2)
|
||||||
multiTxs[0] = transfer.GenerateTestBridgeMultiTransaction(trs[0], trs[1])
|
multiTxs[0] = transfer.GenerateTestBridgeMultiTransaction(trs[0], trs[1])
|
||||||
multiTxs[1] = transfer.GenerateTestSwapMultiTransaction(trs[2], testutils.SntSymbol, 100) // trs[3]
|
multiTxs[1] = transfer.GenerateTestSwapMultiTransaction(trs[2], testutils.SntSymbol, 100) // trs[3]
|
||||||
multiTxs[2] = transfer.GenerateTestSendMultiTransaction(trs[4]) // trs[5]
|
multiTxs[2] = transfer.GenerateTestSendMultiTransaction(trs[4]) // trs[5]
|
||||||
multiTxs[3] = transfer.GenerateTestBridgeMultiTransaction(trs[6], trs[7])
|
multiTxs[3] = transfer.GenerateTestBridgeMultiTransaction(trs[6], trs[7])
|
||||||
multiTxs[4] = transfer.GenerateTestSendMultiTransaction(trs[8]) // trs[9]
|
multiTxs[4] = transfer.GenerateTestSendMultiTransaction(trs[8]) // trs[9]
|
||||||
|
|
||||||
|
allAddresses := append(append(append(tdFromAdds, tdToAddrs...), fromAddrs...), toAddrs...)
|
||||||
|
|
||||||
var lastMT transfer.MultiTransactionIDType
|
var lastMT transfer.MultiTransactionIDType
|
||||||
for i := range trs {
|
for i := range trs {
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
|
@ -677,12 +654,12 @@ func TestGetActivityEntriesFilterByType(t *testing.T) {
|
||||||
filter.Types = allActivityTypesFilter()
|
filter.Types = allActivityTypesFilter()
|
||||||
// Set tr1 to Receive and pendingTr to Send; rest of two MT remain default Send
|
// Set tr1 to Receive and pendingTr to Send; rest of two MT remain default Send
|
||||||
addresses := []eth.Address{td.tr1.To, td.pendingTr.From, td.multiTx1.FromAddress, td.multiTx2.FromAddress, trs[0].From, trs[2].From, trs[4].From, trs[6].From, trs[8].From, trsSpecial[0].To, trsSpecial[1].From}
|
addresses := []eth.Address{td.tr1.To, td.pendingTr.From, td.multiTx1.FromAddress, td.multiTx2.FromAddress, trs[0].From, trs[2].From, trs[4].From, trs[6].From, trs[8].From, trsSpecial[0].To, trsSpecial[1].From}
|
||||||
entries, err := getActivityEntries(context.Background(), deps, addresses, []common.ChainID{}, filter, 0, 15)
|
entries, err := getActivityEntries(context.Background(), deps, addresses, false, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 11, len(entries))
|
require.Equal(t, 11, len(entries))
|
||||||
|
|
||||||
filter.Types = []Type{SendAT, SwapAT}
|
filter.Types = []Type{SendAT, SwapAT}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, addresses, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, addresses, false, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
// 3 from td Send + 2 trs MT Send + 1 (swap)
|
// 3 from td Send + 2 trs MT Send + 1 (swap)
|
||||||
require.Equal(t, 6, len(entries))
|
require.Equal(t, 6, len(entries))
|
||||||
|
@ -697,7 +674,7 @@ func TestGetActivityEntriesFilterByType(t *testing.T) {
|
||||||
require.Equal(t, 0, bridgeCount)
|
require.Equal(t, 0, bridgeCount)
|
||||||
|
|
||||||
filter.Types = []Type{BridgeAT, ReceiveAT}
|
filter.Types = []Type{BridgeAT, ReceiveAT}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, addresses, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, addresses, false, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 3, len(entries))
|
require.Equal(t, 3, len(entries))
|
||||||
|
|
||||||
|
@ -710,7 +687,7 @@ func TestGetActivityEntriesFilterByType(t *testing.T) {
|
||||||
require.Equal(t, 2, bridgeCount)
|
require.Equal(t, 2, bridgeCount)
|
||||||
|
|
||||||
filter.Types = []Type{MintAT}
|
filter.Types = []Type{MintAT}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, addresses, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, addresses, false, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 1, len(entries))
|
require.Equal(t, 1, len(entries))
|
||||||
|
|
||||||
|
@ -723,7 +700,7 @@ func TestGetActivityEntriesFilterByType(t *testing.T) {
|
||||||
require.Equal(t, 0, bridgeCount)
|
require.Equal(t, 0, bridgeCount)
|
||||||
|
|
||||||
filter.Types = []Type{ContractDeploymentAT}
|
filter.Types = []Type{ContractDeploymentAT}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, addresses, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, addresses, false, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 1, len(entries))
|
require.Equal(t, 1, len(entries))
|
||||||
|
|
||||||
|
@ -737,7 +714,7 @@ func TestGetActivityEntriesFilterByType(t *testing.T) {
|
||||||
|
|
||||||
// Filter with all addresses regression
|
// Filter with all addresses regression
|
||||||
filter.Types = []Type{SendAT}
|
filter.Types = []Type{SendAT}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, allAddressesFilter(), []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 5, len(entries))
|
require.Equal(t, 5, len(entries))
|
||||||
}
|
}
|
||||||
|
@ -753,18 +730,17 @@ func TestGetActivityEntriesFilterByAddresses(t *testing.T) {
|
||||||
transfer.InsertTestTransfer(t, deps.db, trs[i].From, &trs[i])
|
transfer.InsertTestTransfer(t, deps.db, trs[i].From, &trs[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
mockTestAccountsWithAddresses(t, deps.accountsDb, append(append(append(fromTds, toTds...), fromTrs...), toTrs...))
|
allAddresses := append(append(append(fromTds, toTds...), fromTrs...), toTrs...)
|
||||||
|
|
||||||
var filter Filter
|
var filter Filter
|
||||||
|
|
||||||
addressesFilter := allAddressesFilter()
|
entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
entries, err := getActivityEntries(context.Background(), deps, addressesFilter, []common.ChainID{}, filter, 0, 15)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 10, len(entries))
|
require.Equal(t, 10, len(entries))
|
||||||
|
|
||||||
addressesFilter = []eth.Address{td.multiTx1.ToAddress, td.multiTx2.FromAddress, trs[1].From, trs[4].From, trs[3].To}
|
addressesFilter := []eth.Address{td.multiTx1.ToAddress, td.multiTx2.FromAddress, trs[1].From, trs[4].From, trs[3].To}
|
||||||
// The td.multiTx1.ToAddress and trs[3].To are missing not having them as owner address
|
// The td.multiTx1.ToAddress and trs[3].To are missing not having them as owner address
|
||||||
entries, err = getActivityEntries(context.Background(), deps, addressesFilter, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, addressesFilter, false, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 3, len(entries))
|
require.Equal(t, 3, len(entries))
|
||||||
require.Equal(t, Entry{
|
require.Equal(t, Entry{
|
||||||
|
@ -845,16 +821,16 @@ func TestGetActivityEntriesFilterByStatus(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mockTestAccountsWithAddresses(t, deps.accountsDb, append(append(append(fromTds, toTds...), fromTrs...), toTrs...))
|
allAddresses := append(append(append(fromTds, toTds...), fromTrs...), toTrs...)
|
||||||
|
|
||||||
var filter Filter
|
var filter Filter
|
||||||
filter.Statuses = allActivityStatusesFilter()
|
filter.Statuses = allActivityStatusesFilter()
|
||||||
entries, err := getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 11, len(entries))
|
require.Equal(t, 11, len(entries))
|
||||||
|
|
||||||
filter.Statuses = []Status{PendingAS}
|
filter.Statuses = []Status{PendingAS}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 3, len(entries))
|
require.Equal(t, 3, len(entries))
|
||||||
require.Equal(t, td.pendingTr.Hash, entries[2].transaction.Hash)
|
require.Equal(t, td.pendingTr.Hash, entries[2].transaction.Hash)
|
||||||
|
@ -862,24 +838,24 @@ func TestGetActivityEntriesFilterByStatus(t *testing.T) {
|
||||||
require.Equal(t, trs[1].Hash, entries[0].transaction.Hash)
|
require.Equal(t, trs[1].Hash, entries[0].transaction.Hash)
|
||||||
|
|
||||||
filter.Statuses = []Status{FailedAS}
|
filter.Statuses = []Status{FailedAS}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 2, len(entries))
|
require.Equal(t, 2, len(entries))
|
||||||
|
|
||||||
filter.Statuses = []Status{CompleteAS}
|
filter.Statuses = []Status{CompleteAS}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 6, len(entries))
|
require.Equal(t, 6, len(entries))
|
||||||
|
|
||||||
// Finalized is treated as Complete, would need dynamic blockchain status to track the Finalized level
|
// Finalized is treated as Complete, would need dynamic blockchain status to track the Finalized level
|
||||||
filter.Statuses = []Status{FinalizedAS}
|
filter.Statuses = []Status{FinalizedAS}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 6, len(entries))
|
require.Equal(t, 6, len(entries))
|
||||||
|
|
||||||
// Combined filter
|
// Combined filter
|
||||||
filter.Statuses = []Status{FailedAS, PendingAS}
|
filter.Statuses = []Status{FailedAS, PendingAS}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 5, len(entries))
|
require.Equal(t, 5, len(entries))
|
||||||
}
|
}
|
||||||
|
@ -900,29 +876,29 @@ func TestGetActivityEntriesFilterByTokenType(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
mockTestAccountsWithAddresses(t, deps.accountsDb, append(append(append(fromTds, toTds...), fromTrs...), toTrs...))
|
allAddresses := append(append(append(fromTds, toTds...), fromTrs...), toTrs...)
|
||||||
|
|
||||||
var filter Filter
|
var filter Filter
|
||||||
filter.FilterOutAssets = true
|
filter.FilterOutAssets = true
|
||||||
entries, err := getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 0, len(entries))
|
require.Equal(t, 0, len(entries))
|
||||||
|
|
||||||
filter.FilterOutAssets = false
|
filter.FilterOutAssets = false
|
||||||
filter.Assets = allTokensFilter()
|
filter.Assets = allTokensFilter()
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 13, len(entries))
|
require.Equal(t, 13, len(entries))
|
||||||
|
|
||||||
// Native tokens are network agnostic, hence all are returned
|
// Native tokens are network agnostic, hence all are returned
|
||||||
filter.Assets = []Token{{TokenType: Native, ChainID: common.ChainID(transfer.EthMainnet.ChainID)}}
|
filter.Assets = []Token{{TokenType: Native, ChainID: common.ChainID(transfer.EthMainnet.ChainID)}}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 5, len(entries))
|
require.Equal(t, 5, len(entries))
|
||||||
|
|
||||||
// Test that it doesn't break the filter
|
// Test that it doesn't break the filter
|
||||||
filter.Assets = []Token{{TokenType: Erc1155}}
|
filter.Assets = []Token{{TokenType: Erc1155}}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 0, len(entries))
|
require.Equal(t, 0, len(entries))
|
||||||
|
|
||||||
|
@ -931,7 +907,7 @@ func TestGetActivityEntriesFilterByTokenType(t *testing.T) {
|
||||||
ChainID: common.ChainID(transfer.UsdcMainnet.ChainID),
|
ChainID: common.ChainID(transfer.UsdcMainnet.ChainID),
|
||||||
Address: transfer.UsdcMainnet.Address,
|
Address: transfer.UsdcMainnet.Address,
|
||||||
}}
|
}}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
// Two MT for which ChainID is ignored and one transfer on the main net and the Goerli is ignored
|
// Two MT for which ChainID is ignored and one transfer on the main net and the Goerli is ignored
|
||||||
require.Equal(t, 3, len(entries))
|
require.Equal(t, 3, len(entries))
|
||||||
|
@ -957,7 +933,7 @@ func TestGetActivityEntriesFilterByTokenType(t *testing.T) {
|
||||||
ChainID: common.ChainID(transfer.UsdcGoerli.ChainID),
|
ChainID: common.ChainID(transfer.UsdcGoerli.ChainID),
|
||||||
Address: transfer.UsdcGoerli.Address,
|
Address: transfer.UsdcGoerli.Address,
|
||||||
}}
|
}}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
// Two MT for which ChainID is ignored and two transfers on the main net and Goerli
|
// Two MT for which ChainID is ignored and two transfers on the main net and Goerli
|
||||||
require.Equal(t, 4, len(entries))
|
require.Equal(t, 4, len(entries))
|
||||||
|
@ -978,26 +954,26 @@ func TestGetActivityEntriesFilterByToAddresses(t *testing.T) {
|
||||||
transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
|
transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
mockTestAccountsWithAddresses(t, deps.accountsDb, append(append(append(fromTds, toTds...), fromTrs...), toTrs...))
|
allAddresses := append(append(append(fromTds, toTds...), fromTrs...), toTrs...)
|
||||||
|
|
||||||
var filter Filter
|
var filter Filter
|
||||||
filter.CounterpartyAddresses = allAddressesFilter()
|
filter.CounterpartyAddresses = allAddresses
|
||||||
entries, err := getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 10, len(entries))
|
require.Equal(t, 10, len(entries))
|
||||||
|
|
||||||
filter.CounterpartyAddresses = []eth.Address{eth.HexToAddress("0x567890")}
|
filter.CounterpartyAddresses = []eth.Address{eth.HexToAddress("0x567890")}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 0, len(entries))
|
require.Equal(t, 0, len(entries))
|
||||||
|
|
||||||
filter.CounterpartyAddresses = []eth.Address{td.pendingTr.To, td.multiTx2.ToAddress, trs[3].To}
|
filter.CounterpartyAddresses = []eth.Address{td.pendingTr.To, td.multiTx2.ToAddress, trs[3].To}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 3, len(entries))
|
require.Equal(t, 3, len(entries))
|
||||||
|
|
||||||
filter.CounterpartyAddresses = []eth.Address{td.tr1.To, td.pendingTr.From, trs[3].From, trs[5].To}
|
filter.CounterpartyAddresses = []eth.Address{td.tr1.To, td.pendingTr.From, trs[3].From, trs[5].To}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, []common.ChainID{}, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 2, len(entries))
|
require.Equal(t, 2, len(entries))
|
||||||
}
|
}
|
||||||
|
@ -1042,21 +1018,21 @@ func TestGetActivityEntriesFilterByNetworks(t *testing.T) {
|
||||||
recordPresence(trs[i].ChainID, 4+i)
|
recordPresence(trs[i].ChainID, 4+i)
|
||||||
transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
|
transfer.InsertTestTransfer(t, deps.db, trs[i].To, &trs[i])
|
||||||
}
|
}
|
||||||
mockTestAccountsWithAddresses(t, deps.accountsDb, append(append(append(fromTds, toTds...), fromTrs...), toTrs...))
|
allAddresses := append(append(append(fromTds, toTds...), fromTrs...), toTrs...)
|
||||||
|
|
||||||
var filter Filter
|
var filter Filter
|
||||||
chainIDs := allNetworksFilter()
|
chainIDs := allNetworksFilter()
|
||||||
entries, err := getActivityEntries(context.Background(), deps, []eth.Address{}, chainIDs, filter, 0, 15)
|
entries, err := getActivityEntries(context.Background(), deps, allAddresses, true, chainIDs, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 10, len(entries))
|
require.Equal(t, 10, len(entries))
|
||||||
|
|
||||||
chainIDs = []common.ChainID{5674839210}
|
chainIDs = []common.ChainID{5674839210}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, chainIDs, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, chainIDs, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 0, len(entries))
|
require.Equal(t, 0, len(entries))
|
||||||
|
|
||||||
chainIDs = []common.ChainID{td.pendingTr.ChainID, td.multiTx2Tr1.ChainID, trs[3].ChainID}
|
chainIDs = []common.ChainID{td.pendingTr.ChainID, td.multiTx2Tr1.ChainID, trs[3].ChainID}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, []eth.Address{}, chainIDs, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, allAddresses, true, chainIDs, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
expectedResults := make(map[int]int)
|
expectedResults := make(map[int]int)
|
||||||
for _, chainID := range chainIDs {
|
for _, chainID := range chainIDs {
|
||||||
|
@ -1100,25 +1076,25 @@ func TestGetActivityEntriesFilterByNetworksOfSubTransactions(t *testing.T) {
|
||||||
|
|
||||||
var filter Filter
|
var filter Filter
|
||||||
chainIDs := allNetworksFilter()
|
chainIDs := allNetworksFilter()
|
||||||
entries, err := getActivityEntries(context.Background(), deps, toTrs, chainIDs, filter, 0, 15)
|
entries, err := getActivityEntries(context.Background(), deps, toTrs, false, chainIDs, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 3, len(entries))
|
require.Equal(t, 3, len(entries))
|
||||||
|
|
||||||
chainIDs = []common.ChainID{trs[0].ChainID, trs[1].ChainID}
|
chainIDs = []common.ChainID{trs[0].ChainID, trs[1].ChainID}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, toTrs, chainIDs, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, toTrs, false, chainIDs, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 1, len(entries))
|
require.Equal(t, 1, len(entries))
|
||||||
require.Equal(t, entries[0].id, mt1.MultiTransactionID)
|
require.Equal(t, entries[0].id, mt1.MultiTransactionID)
|
||||||
|
|
||||||
// Filter by pending_transactions sub-transacitons
|
// Filter by pending_transactions sub-transacitons
|
||||||
chainIDs = []common.ChainID{trs[2].ChainID}
|
chainIDs = []common.ChainID{trs[2].ChainID}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, toTrs, chainIDs, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, toTrs, false, chainIDs, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 1, len(entries))
|
require.Equal(t, 1, len(entries))
|
||||||
require.Equal(t, entries[0].id, mt1.MultiTransactionID)
|
require.Equal(t, entries[0].id, mt1.MultiTransactionID)
|
||||||
|
|
||||||
chainIDs = []common.ChainID{trs[3].ChainID}
|
chainIDs = []common.ChainID{trs[3].ChainID}
|
||||||
entries, err = getActivityEntries(context.Background(), deps, toTrs, chainIDs, filter, 0, 15)
|
entries, err = getActivityEntries(context.Background(), deps, toTrs, false, chainIDs, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 1, len(entries))
|
require.Equal(t, 1, len(entries))
|
||||||
require.Equal(t, entries[0].id, mt2.MultiTransactionID)
|
require.Equal(t, entries[0].id, mt2.MultiTransactionID)
|
||||||
|
@ -1140,7 +1116,7 @@ func TestGetActivityEntriesCheckToAndFrom(t *testing.T) {
|
||||||
td.multiTx1.FromAddress, td.multiTx2.FromAddress, trs[0].To, trs[1].To}
|
td.multiTx1.FromAddress, td.multiTx2.FromAddress, trs[0].To, trs[1].To}
|
||||||
|
|
||||||
var filter Filter
|
var filter Filter
|
||||||
entries, err := getActivityEntries(context.Background(), deps, addresses, []common.ChainID{}, filter, 0, 15)
|
entries, err := getActivityEntries(context.Background(), deps, addresses, false, []common.ChainID{}, filter, 0, 15)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 6, len(entries))
|
require.Equal(t, 6, len(entries))
|
||||||
|
|
||||||
|
@ -1165,12 +1141,12 @@ func TestGetActivityEntriesCheckContextCancellation(t *testing.T) {
|
||||||
deps, close := setupTestActivityDB(t)
|
deps, close := setupTestActivityDB(t)
|
||||||
defer close()
|
defer close()
|
||||||
|
|
||||||
_, _, _ = fillTestData(t, deps.db)
|
_, fromAddresses, toAddresses := fillTestData(t, deps.db)
|
||||||
|
|
||||||
cancellableCtx, cancelFn := context.WithCancel(context.Background())
|
cancellableCtx, cancelFn := context.WithCancel(context.Background())
|
||||||
cancelFn()
|
cancelFn()
|
||||||
|
|
||||||
activities, err := getActivityEntries(cancellableCtx, deps, []eth.Address{}, []common.ChainID{}, Filter{}, 0, 10)
|
activities, err := getActivityEntries(cancellableCtx, deps, append(fromAddresses, toAddresses...), true, []common.ChainID{}, Filter{}, 0, 10)
|
||||||
require.ErrorIs(t, err, context.Canceled)
|
require.ErrorIs(t, err, context.Canceled)
|
||||||
require.Equal(t, 0, len(activities))
|
require.Equal(t, 0, len(activities))
|
||||||
}
|
}
|
||||||
|
@ -1187,7 +1163,7 @@ func TestGetActivityEntriesNullAddresses(t *testing.T) {
|
||||||
trs[1].MultiTransactionID = trs[0].MultiTransactionID
|
trs[1].MultiTransactionID = trs[0].MultiTransactionID
|
||||||
|
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
transfer.InsertTestTransferWithOptions(t, deps.db, trs[i].To, &trs[i], &transfer.TestTransferOptions{
|
transfer.InsertTestTransferWithOptions(t, deps.db, trs[i].From, &trs[i], &transfer.TestTransferOptions{
|
||||||
NullifyAddresses: []eth.Address{trs[i].To},
|
NullifyAddresses: []eth.Address{trs[i].To},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1195,13 +1171,18 @@ func TestGetActivityEntriesNullAddresses(t *testing.T) {
|
||||||
trs[3].To = eth.Address{}
|
trs[3].To = eth.Address{}
|
||||||
transfer.InsertTestPendingTransaction(t, deps.db, &trs[3])
|
transfer.InsertTestPendingTransaction(t, deps.db, &trs[3])
|
||||||
|
|
||||||
mockTestAccountsWithAddresses(t, deps.accountsDb, []eth.Address{trs[0].From, trs[1].From, trs[2].From, trs[3].From})
|
addresses := []eth.Address{trs[0].From, trs[1].From, trs[2].From, trs[3].From}
|
||||||
|
|
||||||
activities, err := getActivityEntries(context.Background(), deps, allAddressesFilter(), allNetworksFilter(), Filter{}, 0, 10)
|
activities, err := getActivityEntries(context.Background(), deps, addresses, false, allNetworksFilter(), Filter{}, 0, 10)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 3, len(activities))
|
require.Equal(t, 3, len(activities))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetActivityEntries_ErrorIfNoAddress(t *testing.T) {
|
||||||
|
_, err := getActivityEntries(context.Background(), FilterDependencies{}, []eth.Address{}, true, []common.ChainID{}, Filter{}, 0, 10)
|
||||||
|
require.EqualError(t, err, "no addresses provided")
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetTxDetails(t *testing.T) {
|
func TestGetTxDetails(t *testing.T) {
|
||||||
deps, close := setupTestActivityDB(t)
|
deps, close := setupTestActivityDB(t)
|
||||||
defer close()
|
defer close()
|
||||||
|
@ -1296,7 +1277,7 @@ func setupBenchmark(b *testing.B, inMemory bool, resultCount int) (deps FilterDe
|
||||||
|
|
||||||
for i = 0; i < transactionCount-pendingCount; i++ {
|
for i = 0; i < transactionCount-pendingCount; i++ {
|
||||||
trs[i].From = accounts[i%len(accounts)]
|
trs[i].From = accounts[i%len(accounts)]
|
||||||
transfer.InsertTestTransfer(b, deps.db, trs[i].To, &trs[i])
|
transfer.InsertTestTransfer(b, deps.db, trs[i].From, &trs[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
for ; i < transactionCount; i++ {
|
for ; i < transactionCount; i++ {
|
||||||
|
@ -1304,7 +1285,6 @@ func setupBenchmark(b *testing.B, inMemory bool, resultCount int) (deps FilterDe
|
||||||
transfer.InsertTestPendingTransaction(b, deps.db, &trs[i])
|
transfer.InsertTestPendingTransaction(b, deps.db, &trs[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
mockTestAccountsWithAddresses(b, deps.accountsDb, accounts)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1312,7 +1292,7 @@ func BenchmarkGetActivityEntries(bArg *testing.B) {
|
||||||
type params struct {
|
type params struct {
|
||||||
inMemory bool
|
inMemory bool
|
||||||
resultCount int
|
resultCount int
|
||||||
generateTestParameters func([]eth.Address) (addresses []eth.Address, filter *Filter, startIndex int)
|
generateTestParameters func([]eth.Address) (addresses []eth.Address, allAddresses bool, filter *Filter, startIndex int)
|
||||||
}
|
}
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -1323,8 +1303,8 @@ func BenchmarkGetActivityEntries(bArg *testing.B) {
|
||||||
params{
|
params{
|
||||||
true,
|
true,
|
||||||
10,
|
10,
|
||||||
func([]eth.Address) ([]eth.Address, *Filter, int) {
|
func(addresses []eth.Address) ([]eth.Address, bool, *Filter, int) {
|
||||||
return allAddressesFilter(), &Filter{}, 0
|
return addresses, true, &Filter{}, 0
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1333,8 +1313,8 @@ func BenchmarkGetActivityEntries(bArg *testing.B) {
|
||||||
params{
|
params{
|
||||||
false,
|
false,
|
||||||
10,
|
10,
|
||||||
func([]eth.Address) ([]eth.Address, *Filter, int) {
|
func(addresses []eth.Address) ([]eth.Address, bool, *Filter, int) {
|
||||||
return allAddressesFilter(), &Filter{}, 0
|
return addresses, true, &Filter{}, 0
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1343,18 +1323,8 @@ func BenchmarkGetActivityEntries(bArg *testing.B) {
|
||||||
params{
|
params{
|
||||||
false,
|
false,
|
||||||
10,
|
10,
|
||||||
func(addresses []eth.Address) ([]eth.Address, *Filter, int) {
|
func(addresses []eth.Address) ([]eth.Address, bool, *Filter, int) {
|
||||||
return allAddressesFilter(), &Filter{}, 200
|
return addresses, true, &Filter{}, 200
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"SSD_AllAddresses",
|
|
||||||
params{
|
|
||||||
false,
|
|
||||||
10,
|
|
||||||
func(addresses []eth.Address) ([]eth.Address, *Filter, int) {
|
|
||||||
return addresses, &Filter{}, 0
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1363,8 +1333,8 @@ func BenchmarkGetActivityEntries(bArg *testing.B) {
|
||||||
params{
|
params{
|
||||||
false,
|
false,
|
||||||
10,
|
10,
|
||||||
func(addresses []eth.Address) ([]eth.Address, *Filter, int) {
|
func(addresses []eth.Address) ([]eth.Address, bool, *Filter, int) {
|
||||||
return addresses, &Filter{CounterpartyAddresses: addresses[3:]}, 0
|
return addresses, true, &Filter{CounterpartyAddresses: addresses[3:]}, 0
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1373,8 +1343,8 @@ func BenchmarkGetActivityEntries(bArg *testing.B) {
|
||||||
params{
|
params{
|
||||||
false,
|
false,
|
||||||
10,
|
10,
|
||||||
func(addresses []eth.Address) ([]eth.Address, *Filter, int) {
|
func(addresses []eth.Address) ([]eth.Address, bool, *Filter, int) {
|
||||||
return addresses[0:1], &Filter{}, 0
|
return addresses[0:1], false, &Filter{}, 0
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1385,14 +1355,14 @@ func BenchmarkGetActivityEntries(bArg *testing.B) {
|
||||||
|
|
||||||
const resultCount = 10
|
const resultCount = 10
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
addresses, filter, startIndex := tc.params.generateTestParameters(accounts)
|
addresses, allAddresses, filter, startIndex := tc.params.generateTestParameters(accounts)
|
||||||
bArg.Run(tc.name, func(b *testing.B) {
|
bArg.Run(tc.name, func(b *testing.B) {
|
||||||
// Reset timer after setup
|
// Reset timer after setup
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
||||||
// Run benchmark
|
// Run benchmark
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
res, err := getActivityEntries(context.Background(), deps, addresses, allNetworksFilter(), *filter, startIndex, resultCount)
|
res, err := getActivityEntries(context.Background(), deps, addresses, allAddresses, allNetworksFilter(), *filter, startIndex, resultCount)
|
||||||
if err != nil || len(res) != resultCount {
|
if err != nil || len(res) != resultCount {
|
||||||
b.Error(err)
|
b.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -1400,59 +1370,3 @@ func BenchmarkGetActivityEntries(bArg *testing.B) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateWalletKeypairsAccountsTable(t *testing.T) {
|
|
||||||
// initialize
|
|
||||||
appDb, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
walletDb, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
accountsAppDb, err := accounts.NewDB(appDb)
|
|
||||||
require.NoError(t, err)
|
|
||||||
accountsWalletDb, err := accounts.NewDB(walletDb)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Check initially empty
|
|
||||||
addressesApp, err := accountsAppDb.GetWalletAddresses()
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Empty(t, addressesApp)
|
|
||||||
addressesWallet, err := accountsWalletDb.GetWalletAddresses()
|
|
||||||
require.Error(t, err) // no such table error
|
|
||||||
require.Empty(t, addressesWallet)
|
|
||||||
|
|
||||||
// Insert 2 addresses in app db, but only 1 is a wallet
|
|
||||||
addresses := []types.Address{{0x01}, {0x02}, {0x03}}
|
|
||||||
accounts := []*accounts.Account{
|
|
||||||
{Address: addresses[0], Chat: true, Wallet: true},
|
|
||||||
{Address: addresses[1], Wallet: true},
|
|
||||||
{Address: addresses[2]},
|
|
||||||
}
|
|
||||||
err = accountsAppDb.SaveOrUpdateAccounts(accounts, false)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Check only 2 wallet accs is returned in app db
|
|
||||||
addressesApp, err = accountsAppDb.GetWalletAddresses()
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, addressesApp, 2)
|
|
||||||
|
|
||||||
// update wallet DB
|
|
||||||
err = updateKeypairsAccountsTable(accountsAppDb, walletDb)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Check only 2 wallet acc is returned in wallet db
|
|
||||||
var count int
|
|
||||||
err = walletDb.QueryRow(fmt.Sprintf("SELECT count(address) FROM %s", keypairAccountsTable)).Scan(&count)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, count, 2)
|
|
||||||
|
|
||||||
// Compare addresses between app and wallet db
|
|
||||||
rows, err := walletDb.Query(fmt.Sprintf("SELECT address FROM %s", keypairAccountsTable))
|
|
||||||
require.NoError(t, err)
|
|
||||||
for rows.Next() {
|
|
||||||
var address types.Address
|
|
||||||
err = rows.Scan(&address)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Contains(t, addresses, address)
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
}
|
|
||||||
|
|
|
@ -68,10 +68,6 @@ func allTokensFilter() []Token {
|
||||||
return []Token{}
|
return []Token{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func allAddressesFilter() []eth.Address {
|
|
||||||
return []eth.Address{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func allNetworksFilter() []common.ChainID {
|
func allNetworksFilter() []common.ChainID {
|
||||||
return []common.ChainID{}
|
return []common.ChainID{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
-- Query includes duplicates, will return multiple rows for the same transaction if both to and from addresses are in the address list.
|
-- Query includes duplicates, will return multiple rows for the same transaction if both to and from addresses are in the address list.
|
||||||
--
|
--
|
||||||
-- The addresses list will have priority in deciding the source of the duplicate transaction; see filter_addresses temp table
|
|
||||||
-- TODO: #11980
|
|
||||||
-- However, if the addresses list is empty, and all addresses should be included, the accounts table will be used
|
|
||||||
--
|
|
||||||
-- The switch for tr_type is used to de-conflict the source for the two entries for the same transaction
|
-- The switch for tr_type is used to de-conflict the source for the two entries for the same transaction
|
||||||
--
|
--
|
||||||
-- UNION ALL is used to avoid the overhead of DISTINCT given that we don't expect to have duplicate entries outside the sender and receiver addresses being in the list which is handled separately
|
-- UNION ALL is used to avoid the overhead of DISTINCT given that we don't expect to have duplicate entries outside the sender and receiver addresses being in the list which is handled separately
|
||||||
|
@ -43,13 +39,14 @@ WITH filter_conditions AS (
|
||||||
? AS includeAllTokenTypeAssets,
|
? AS includeAllTokenTypeAssets,
|
||||||
? AS includeAllNetworks,
|
? AS includeAllNetworks,
|
||||||
? AS pendingStatus,
|
? AS pendingStatus,
|
||||||
"0000000000000000000000000000000000000000" AS zeroAddress
|
'0000000000000000000000000000000000000000' AS zeroAddress
|
||||||
),
|
),
|
||||||
|
-- This UNION between CTE and TEMP TABLE acts as an optimization. As soon as we drop one or use them interchangeably the performance drops significantly.
|
||||||
filter_addresses(address) AS (
|
filter_addresses(address) AS (
|
||||||
SELECT
|
SELECT
|
||||||
HEX(address)
|
address
|
||||||
FROM
|
FROM
|
||||||
%s
|
filter_addresses_table
|
||||||
WHERE
|
WHERE
|
||||||
(
|
(
|
||||||
SELECT
|
SELECT
|
||||||
|
@ -209,7 +206,7 @@ WHERE
|
||||||
AND NOT (
|
AND NOT (
|
||||||
tr_type = fromTrType
|
tr_type = fromTrType
|
||||||
and transfers.tx_to_address IS NULL
|
and transfers.tx_to_address IS NULL
|
||||||
AND transfers.type = "eth"
|
AND transfers.type = 'eth'
|
||||||
AND transfers.contract_address IS NOT NULL
|
AND transfers.contract_address IS NOT NULL
|
||||||
AND HEX(transfers.contract_address) != zeroAddress
|
AND HEX(transfers.contract_address) != zeroAddress
|
||||||
)
|
)
|
||||||
|
@ -219,7 +216,7 @@ WHERE
|
||||||
AND tr_type = toTrType
|
AND tr_type = toTrType
|
||||||
AND NOT (
|
AND NOT (
|
||||||
tr_type = toTrType
|
tr_type = toTrType
|
||||||
AND transfers.type = "erc721"
|
AND transfers.type = 'erc721'
|
||||||
AND (
|
AND (
|
||||||
transfers.tx_from_address IS NULL
|
transfers.tx_from_address IS NULL
|
||||||
OR HEX(transfers.tx_from_address) = zeroAddress
|
OR HEX(transfers.tx_from_address) = zeroAddress
|
||||||
|
@ -230,7 +227,7 @@ WHERE
|
||||||
filterActivityTypeContractDeployment
|
filterActivityTypeContractDeployment
|
||||||
AND tr_type = fromTrType
|
AND tr_type = fromTrType
|
||||||
AND transfers.tx_to_address IS NULL
|
AND transfers.tx_to_address IS NULL
|
||||||
AND transfers.type = "eth"
|
AND transfers.type = 'eth'
|
||||||
AND transfers.contract_address IS NOT NULL
|
AND transfers.contract_address IS NOT NULL
|
||||||
AND HEX(transfers.contract_address) != zeroAddress
|
AND HEX(transfers.contract_address) != zeroAddress
|
||||||
AND (
|
AND (
|
||||||
|
@ -241,7 +238,7 @@ WHERE
|
||||||
OR (
|
OR (
|
||||||
filterActivityTypeMint
|
filterActivityTypeMint
|
||||||
AND tr_type = toTrType
|
AND tr_type = toTrType
|
||||||
AND transfers.type = "erc721"
|
AND transfers.type = 'erc721'
|
||||||
AND (
|
AND (
|
||||||
transfers.tx_from_address IS NULL
|
transfers.tx_from_address IS NULL
|
||||||
OR HEX(transfers.tx_from_address) = zeroAddress
|
OR HEX(transfers.tx_from_address) = zeroAddress
|
||||||
|
@ -265,11 +262,11 @@ WHERE
|
||||||
AND (
|
AND (
|
||||||
includeAllTokenTypeAssets
|
includeAllTokenTypeAssets
|
||||||
OR (
|
OR (
|
||||||
transfers.type = "eth"
|
transfers.type = 'eth'
|
||||||
AND ("ETH" IN assets_token_codes)
|
AND ('ETH' IN assets_token_codes)
|
||||||
)
|
)
|
||||||
OR (
|
OR (
|
||||||
transfers.type = "erc20"
|
transfers.type = 'erc20'
|
||||||
AND (
|
AND (
|
||||||
(
|
(
|
||||||
transfers.network_id,
|
transfers.network_id,
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
||||||
"github.com/status-im/status-go/multiaccounts/accounts"
|
|
||||||
"github.com/status-im/status-go/services/wallet/async"
|
"github.com/status-im/status-go/services/wallet/async"
|
||||||
"github.com/status-im/status-go/services/wallet/collectibles"
|
"github.com/status-im/status-go/services/wallet/collectibles"
|
||||||
w_common "github.com/status-im/status-go/services/wallet/common"
|
w_common "github.com/status-im/status-go/services/wallet/common"
|
||||||
|
@ -43,9 +42,9 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Service provides an async interface, ensuring only one filter request, of each type, is running at a time. It also provides lazy load of NFT info and token mapping
|
||||||
type Service struct {
|
type Service struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
accountsDB *accounts.Database
|
|
||||||
tokenManager token.ManagerInterface
|
tokenManager token.ManagerInterface
|
||||||
collectibles collectibles.ManagerInterface
|
collectibles collectibles.ManagerInterface
|
||||||
eventFeed *event.Feed
|
eventFeed *event.Feed
|
||||||
|
@ -53,10 +52,9 @@ type Service struct {
|
||||||
scheduler *async.MultiClientScheduler
|
scheduler *async.MultiClientScheduler
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(db *sql.DB, tokenManager token.ManagerInterface, collectibles collectibles.ManagerInterface, eventFeed *event.Feed, accountsDb *accounts.Database) *Service {
|
func NewService(db *sql.DB, tokenManager token.ManagerInterface, collectibles collectibles.ManagerInterface, eventFeed *event.Feed) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
db: db,
|
db: db,
|
||||||
accountsDB: accountsDb,
|
|
||||||
tokenManager: tokenManager,
|
tokenManager: tokenManager,
|
||||||
collectibles: collectibles,
|
collectibles: collectibles,
|
||||||
eventFeed: eventFeed,
|
eventFeed: eventFeed,
|
||||||
|
@ -82,11 +80,13 @@ type FilterResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterActivityAsync allows only one filter task to run at a time
|
// FilterActivityAsync allows only one filter task to run at a time
|
||||||
// and it cancels the current one if a new one is started
|
// it cancels the current one if a new one is started
|
||||||
|
// and should not expect other owners to have data in one of the queried tables
|
||||||
|
//
|
||||||
// All calls will trigger an EventActivityFilteringDone event with the result of the filtering
|
// All calls will trigger an EventActivityFilteringDone event with the result of the filtering
|
||||||
func (s *Service) FilterActivityAsync(requestID int32, addresses []common.Address, chainIDs []w_common.ChainID, filter Filter, offset int, limit int) {
|
func (s *Service) FilterActivityAsync(requestID int32, addresses []common.Address, allAddresses bool, chainIDs []w_common.ChainID, filter Filter, offset int, limit int) {
|
||||||
s.scheduler.Enqueue(requestID, filterTask, func(ctx context.Context) (interface{}, error) {
|
s.scheduler.Enqueue(requestID, filterTask, func(ctx context.Context) (interface{}, error) {
|
||||||
activities, err := getActivityEntries(ctx, s.getDeps(), addresses, chainIDs, filter, offset, limit)
|
activities, err := getActivityEntries(ctx, s.getDeps(), addresses, allAddresses, chainIDs, filter, offset, limit)
|
||||||
return activities, err
|
return activities, err
|
||||||
}, func(result interface{}, taskType async.TaskType, err error) {
|
}, func(result interface{}, taskType async.TaskType, err error) {
|
||||||
res := FilterResponse{
|
res := FilterResponse{
|
||||||
|
@ -241,8 +241,7 @@ func (s *Service) Stop() {
|
||||||
|
|
||||||
func (s *Service) getDeps() FilterDependencies {
|
func (s *Service) getDeps() FilterDependencies {
|
||||||
return FilterDependencies{
|
return FilterDependencies{
|
||||||
db: s.db,
|
db: s.db,
|
||||||
accountsDb: s.accountsDB,
|
|
||||||
tokenSymbol: func(t Token) string {
|
tokenSymbol: func(t Token) string {
|
||||||
info := s.tokenManager.LookupTokenIdentity(uint64(t.ChainID), t.Address, t.TokenType == Native)
|
info := s.tokenManager.LookupTokenIdentity(uint64(t.ChainID), t.Address, t.TokenType == Native)
|
||||||
if info == nil {
|
if info == nil {
|
||||||
|
|
|
@ -63,7 +63,7 @@ func setupTestService(tb testing.TB) (service *Service, eventFeed *event.Feed, t
|
||||||
eventFeed = new(event.Feed)
|
eventFeed = new(event.Feed)
|
||||||
tokenMock = &mockTokenManager{}
|
tokenMock = &mockTokenManager{}
|
||||||
collectiblesMock = &mockCollectiblesManager{}
|
collectiblesMock = &mockCollectiblesManager{}
|
||||||
service = NewService(db, tokenMock, collectiblesMock, eventFeed, nil)
|
service = NewService(db, tokenMock, collectiblesMock, eventFeed)
|
||||||
|
|
||||||
return service, eventFeed, tokenMock, collectiblesMock, func() {
|
return service, eventFeed, tokenMock, collectiblesMock, func() {
|
||||||
require.NoError(tb, db.Close())
|
require.NoError(tb, db.Close())
|
||||||
|
@ -79,8 +79,8 @@ type arg struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// insertStubTransfersWithCollectibles will insert nil if tokenIDStr is empty
|
// insertStubTransfersWithCollectibles will insert nil if tokenIDStr is empty
|
||||||
func insertStubTransfersWithCollectibles(t *testing.T, db *sql.DB, args []arg) {
|
func insertStubTransfersWithCollectibles(t *testing.T, db *sql.DB, args []arg) (fromAddresses, toAddresses []eth.Address) {
|
||||||
trs, _, _ := transfer.GenerateTestTransfers(t, db, 0, len(args))
|
trs, fromAddresses, toAddresses := transfer.GenerateTestTransfers(t, db, 0, len(args))
|
||||||
for i := range args {
|
for i := range args {
|
||||||
trs[i].ChainID = args[i].chainID
|
trs[i].ChainID = args[i].chainID
|
||||||
if args[i].tokenIDStr == "" {
|
if args[i].tokenIDStr == "" {
|
||||||
|
@ -96,6 +96,7 @@ func insertStubTransfersWithCollectibles(t *testing.T, db *sql.DB, args []arg) {
|
||||||
TokenID: args[i].tokenID,
|
TokenID: args[i].tokenID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
return fromAddresses, toAddresses
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestService_UpdateCollectibleInfo(t *testing.T) {
|
func TestService_UpdateCollectibleInfo(t *testing.T) {
|
||||||
|
@ -108,7 +109,7 @@ func TestService_UpdateCollectibleInfo(t *testing.T) {
|
||||||
{5, "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a", "", nil, nil},
|
{5, "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a", "", nil, nil},
|
||||||
{5, "0xA2838FDA19EB6EED3F8B9EFF411D4CD7D2DE0313", "0x0F", nil, nil},
|
{5, "0xA2838FDA19EB6EED3F8B9EFF411D4CD7D2DE0313", "0x0F", nil, nil},
|
||||||
}
|
}
|
||||||
insertStubTransfersWithCollectibles(t, s.db, args)
|
fromAddresses, toAddresses := insertStubTransfersWithCollectibles(t, s.db, args)
|
||||||
|
|
||||||
ch := make(chan walletevent.Event)
|
ch := make(chan walletevent.Event)
|
||||||
sub := e.Subscribe(ch)
|
sub := e.Subscribe(ch)
|
||||||
|
@ -147,7 +148,7 @@ func TestService_UpdateCollectibleInfo(t *testing.T) {
|
||||||
},
|
},
|
||||||
}, nil).Once()
|
}, nil).Once()
|
||||||
|
|
||||||
s.FilterActivityAsync(0, allAddressesFilter(), allNetworksFilter(), Filter{}, 0, 3)
|
s.FilterActivityAsync(0, append(fromAddresses, toAddresses...), true, allNetworksFilter(), Filter{}, 0, 3)
|
||||||
|
|
||||||
filterResponseCount := 0
|
filterResponseCount := 0
|
||||||
var updates []EntryData
|
var updates []EntryData
|
||||||
|
@ -190,43 +191,36 @@ func TestService_UpdateCollectibleInfo_Error(t *testing.T) {
|
||||||
{5, "0xA2838FDA19EB6EED3F8B9EFF411D4CD7D2DE0313", "0x762AD3E4934E687F8701F24C7274E5209213FD6208FF952ACEB325D028866949", nil, nil},
|
{5, "0xA2838FDA19EB6EED3F8B9EFF411D4CD7D2DE0313", "0x762AD3E4934E687F8701F24C7274E5209213FD6208FF952ACEB325D028866949", nil, nil},
|
||||||
{5, "0xA2838FDA19EB6EED3F8B9EFF411D4CD7D2DE0313", "0x0D", nil, nil},
|
{5, "0xA2838FDA19EB6EED3F8B9EFF411D4CD7D2DE0313", "0x0D", nil, nil},
|
||||||
}
|
}
|
||||||
insertStubTransfersWithCollectibles(t, s.db, args)
|
|
||||||
|
|
||||||
ch := make(chan walletevent.Event)
|
ch := make(chan walletevent.Event, 4)
|
||||||
sub := e.Subscribe(ch)
|
sub := e.Subscribe(ch)
|
||||||
|
|
||||||
|
fromAddresses, toAddresses := insertStubTransfersWithCollectibles(t, s.db, args)
|
||||||
|
|
||||||
c.On("FetchAssetsByCollectibleUniqueID", mock.Anything).Return(nil, thirdparty.ErrChainIDNotSupported).Once()
|
c.On("FetchAssetsByCollectibleUniqueID", mock.Anything).Return(nil, thirdparty.ErrChainIDNotSupported).Once()
|
||||||
|
|
||||||
s.FilterActivityAsync(0, allAddressesFilter(), allNetworksFilter(), Filter{}, 0, 5)
|
s.FilterActivityAsync(0, append(fromAddresses, toAddresses...), true, allNetworksFilter(), Filter{}, 0, 5)
|
||||||
|
|
||||||
filterResponseCount := 0
|
filterResponseCount := 0
|
||||||
updatesCount := 0
|
updatesCount := 0
|
||||||
|
|
||||||
select {
|
for i := 0; i < 2; i++ {
|
||||||
case res := <-ch:
|
select {
|
||||||
switch res.Type {
|
case res := <-ch:
|
||||||
case EventActivityFilteringDone:
|
switch res.Type {
|
||||||
var payload FilterResponse
|
case EventActivityFilteringDone:
|
||||||
err := json.Unmarshal([]byte(res.Message), &payload)
|
var payload FilterResponse
|
||||||
require.NoError(t, err)
|
err := json.Unmarshal([]byte(res.Message), &payload)
|
||||||
require.Equal(t, ErrorCodeSuccess, payload.ErrorCode)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 2, len(payload.Activities))
|
require.Equal(t, ErrorCodeSuccess, payload.ErrorCode)
|
||||||
filterResponseCount++
|
require.Equal(t, 2, len(payload.Activities))
|
||||||
case EventActivityFilteringUpdate:
|
filterResponseCount++
|
||||||
updatesCount++
|
case EventActivityFilteringUpdate:
|
||||||
|
updatesCount++
|
||||||
|
}
|
||||||
|
case <-time.NewTimer(20 * time.Millisecond).C:
|
||||||
|
// We wait to ensure the EventActivityFilteringUpdate is never sent
|
||||||
}
|
}
|
||||||
case <-time.NewTimer(100 * time.Millisecond).C:
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case res := <-ch:
|
|
||||||
switch res.Type {
|
|
||||||
case EventActivityFilteringDone:
|
|
||||||
filterResponseCount++
|
|
||||||
case EventActivityFilteringUpdate:
|
|
||||||
updatesCount++
|
|
||||||
}
|
|
||||||
case <-time.NewTimer(100 * time.Microsecond).C:
|
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equal(t, 1, filterResponseCount)
|
require.Equal(t, 1, filterResponseCount)
|
||||||
|
|
|
@ -570,10 +570,10 @@ func (api *API) FetchAllCurrencyFormats() (currency.FormatPerSymbol, error) {
|
||||||
return api.s.currency.FetchAllCurrencyFormats()
|
return api.s.currency.FetchAllCurrencyFormats()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) FilterActivityAsync(requestID int32, addresses []common.Address, chainIDs []wcommon.ChainID, filter activity.Filter, offset int, limit int) error {
|
func (api *API) FilterActivityAsync(requestID int32, addresses []common.Address, allAddresses bool, chainIDs []wcommon.ChainID, filter activity.Filter, offset int, limit int) error {
|
||||||
log.Debug("wallet.api.FilterActivityAsync", "requestID", requestID, "addr.count", len(addresses), "chainIDs.count", len(chainIDs), "offset", offset, "limit", limit)
|
log.Debug("wallet.api.FilterActivityAsync", "requestID", requestID, "addr.count", len(addresses), "allAddresses", allAddresses, "chainIDs.count", len(chainIDs), "offset", offset, "limit", limit)
|
||||||
|
|
||||||
api.s.activity.FilterActivityAsync(requestID, addresses, chainIDs, filter, offset, limit)
|
api.s.activity.FilterActivityAsync(requestID, addresses, allAddresses, chainIDs, filter, offset, limit)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ func NewService(
|
||||||
collectiblesManager := collectibles.NewManager(db, rpcClient, contractOwnershipProviders, accountOwnershipProviders, collectibleDataProviders, collectionDataProviders, openseaClient)
|
collectiblesManager := collectibles.NewManager(db, rpcClient, contractOwnershipProviders, accountOwnershipProviders, collectibleDataProviders, collectionDataProviders, openseaClient)
|
||||||
collectibles := collectibles.NewService(db, feed, accountsDB, accountFeed, rpcClient.NetworkManager, collectiblesManager)
|
collectibles := collectibles.NewService(db, feed, accountsDB, accountFeed, rpcClient.NetworkManager, collectiblesManager)
|
||||||
|
|
||||||
activity := activity.NewService(db, tokenManager, collectiblesManager, feed, accountsDB)
|
activity := activity.NewService(db, tokenManager, collectiblesManager, feed)
|
||||||
|
|
||||||
return &Service{
|
return &Service{
|
||||||
db: db,
|
db: db,
|
||||||
|
|
Loading…
Reference in New Issue