fix(wallet) fix filtering failing with NULL values in to_address

Added test to validate the fix

Also change JOIN to LEFT JOIN between `multi_transactions` and `transactions` table so that we return all entries from `multi_transactions` table even if there is no matching entry in `transactions` table, which might be the case for multi transactions that that could not be detected. This will postpone the error case until we get into details of the multi transaction.

Updates status-desktop #11233
This commit is contained in:
Stefan 2023-07-04 13:01:45 +01:00 committed by Stefan Dunca
parent 511d6bfc54
commit 293fa9d248
3 changed files with 43 additions and 10 deletions

View File

@ -298,8 +298,7 @@ const (
FROM
transfers
WHERE transfers.multi_transaction_id != 0
GROUP BY
transfers.multi_transaction_id
GROUP BY transfers.multi_transaction_id
),
pending_status AS (
SELECT
@ -464,7 +463,7 @@ const (
multi_transactions.from_asset AS from_token_code,
multi_transactions.to_asset AS to_token_code
FROM multi_transactions, filter_conditions
JOIN tr_status ON multi_transactions.ROWID = tr_status.multi_transaction_id
LEFT JOIN tr_status ON multi_transactions.ROWID = tr_status.multi_transaction_id
LEFT JOIN pending_status ON multi_transactions.ROWID = pending_status.multi_transaction_id
WHERE
((startFilterDisabled OR multi_transactions.timestamp >= startTimestamp)
@ -599,18 +598,22 @@ func getActivityEntries(ctx context.Context, deps FilterDependencies, addresses
var timestamp int64
var dbMtType, dbTrType sql.NullByte
var toAddress, fromAddress eth.Address
var toAddressDB sql.RawBytes
var tokenAddress *eth.Address
var aggregatedStatus int
var dbTrAmount sql.NullString
var dbMtFromAmount, dbMtToAmount sql.NullString
var tokenCode, fromTokenCode, toTokenCode sql.NullString
err := rows.Scan(&transferHash, &pendingHash, &chainID, &multiTxID, &timestamp, &dbMtType, &dbTrType, &fromAddress,
&toAddress, &dbTrAmount, &dbMtFromAmount, &dbMtToAmount, &aggregatedStatus, &aggregatedCount,
&toAddressDB, &dbTrAmount, &dbMtFromAmount, &dbMtToAmount, &aggregatedStatus, &aggregatedCount,
&tokenAddress, &tokenCode, &fromTokenCode, &toTokenCode)
if err != nil {
return nil, err
}
if len(toAddressDB) > 0 {
toAddress = eth.BytesToAddress(toAddressDB)
}
getActivityType := func(trType sql.NullByte) (activityType Type, filteredAddress eth.Address) {
if trType.Valid {
if trType.Byte == fromTrType {
@ -619,7 +622,7 @@ func getActivityEntries(ctx context.Context, deps FilterDependencies, addresses
return ReceiveAT, toAddress
}
}
log.Warn(fmt.Sprintf("unexpected activity type. Missing [%s, %s] in the addresses table?", fromAddress, toAddress))
log.Warn(fmt.Sprintf("unexpected activity type. Missing from [%s] or to [%s] in addresses?", fromAddress, toAddress))
return ReceiveAT, toAddress
}

View File

@ -889,3 +889,31 @@ func TestGetActivityEntriesCheckContextCancellation(t *testing.T) {
require.ErrorIs(t, err, context.Canceled)
require.Equal(t, 0, len(activities))
}
func TestGetActivityEntriesNullAddresses(t *testing.T) {
deps, close := setupTestActivityDB(t)
defer close()
// Add 6 extractable transactions
trs, _, _ := transfer.GenerateTestTransfers(t, deps.db, 0, 4)
multiTx := transfer.GenerateTestBridgeMultiTransaction(trs[0], trs[1])
multiTx.ToAddress = eth_common.Address{}
trs[0].MultiTransactionID = transfer.InsertTestMultiTransaction(t, deps.db, &multiTx)
trs[1].MultiTransactionID = trs[0].MultiTransactionID
for i := 0; i < 3; i++ {
transfer.InsertTestTransferWithOptions(t, deps.db, trs[i].To, &trs[i], &transfer.TestTransferOptions{
NullifyAddresses: []eth_common.Address{trs[i].To},
})
}
trs[3].To = eth_common.Address{}
transfer.InsertTestPendingTransaction(t, deps.db, &trs[3])
mockTestAccountsWithAddresses(t, deps.db, []eth_common.Address{trs[0].From, trs[1].From, trs[2].From, trs[3].From})
activities, err := getActivityEntries(context.Background(), deps, allAddressesFilter(), allNetworksFilter(), Filter{}, 0, 10)
require.NoError(t, err)
require.Equal(t, 3, len(activities))
}

View File

@ -93,7 +93,7 @@ func (s *Service) FilterActivityAsync(ctx context.Context, addresses []common.Ad
res.ErrorCode = ErrorCodeSuccess
}
s.sendResponseEvent(EventActivityFilteringDone, res)
s.sendResponseEvent(EventActivityFilteringDone, res, err)
})
}
@ -126,7 +126,7 @@ func (s *Service) GetRecipientsAsync(ctx context.Context, offset int, limit int)
res.ErrorCode = ErrorCodeFailed
}
s.sendResponseEvent(EventActivityGetRecipientsDone, result)
s.sendResponseEvent(EventActivityGetRecipientsDone, result, err)
})
}
@ -151,7 +151,7 @@ func (s *Service) GetOldestTimestampAsync(ctx context.Context, addresses []commo
res.ErrorCode = ErrorCodeSuccess
}
s.sendResponseEvent(EventActivityGetOldestTimestampDone, res)
s.sendResponseEvent(EventActivityGetOldestTimestampDone, res, err)
})
}
@ -192,10 +192,12 @@ func (s *Service) getDeps() FilterDependencies {
}
}
func (s *Service) sendResponseEvent(eventType walletevent.EventType, payloadObj interface{}) {
func (s *Service) sendResponseEvent(eventType walletevent.EventType, payloadObj interface{}, resErr error) {
payload, err := json.Marshal(payloadObj)
if err != nil {
log.Error("Error marshaling response: %v", err)
log.Error("Error marshaling response: %v; result error: %w", err, resErr)
} else {
err = resErr
}
log.Debug("wallet.api.activity.Service RESPONSE", "eventType", eventType, "error", err, "payload.len", len(payload))