Make the getENSName calls async (#16099)

* wip: make the getENSName calls async

* fix: login to the app takes forever

Resolving ens name sometimes, most likely due to network congestion can be really slow,
that results in slow app loading, especially if user has more accounts, cause the app checks
ens name existence for each account.

This PR does that check in an async way.

Fixes #16086

* chore: async check for ens name existence when adding new accounts

---------

Co-authored-by: Sale Djenic <aleksandardjenic@status.im>
This commit is contained in:
Jonathan Rainville 2024-08-14 13:25:42 -04:00 committed by GitHub
parent c63c114e5c
commit 6cd9fa91e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 68 additions and 13 deletions

View File

@ -257,3 +257,28 @@ proc getTokenBalanceHistoryDataTask*(argEncoded: string) {.gcsafe, nimcall.} =
"error": e.msg, "error": e.msg,
} }
arg.finish(output) arg.finish(output)
#################################################
# Async get ENS names for account
#################################################
type
FetchENSNamesForAddressesTaskArg = ref object of QObjectTaskArg
chainId: int
addresses: seq[string]
proc fetchENSNamesForAddressesTask*(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[FetchENSNamesForAddressesTaskArg](argEncoded)
var response = %* {
"result": [],
"error": "",
}
try:
var result = newJobject()
for address in arg.addresses:
let name = getEnsName(address, arg.chainId)
result[address] = %name
response["result"] = result
except Exception as e:
response["error"] = %* e.msg
arg.finish(response)

View File

@ -56,6 +56,8 @@ QtObject:
proc handleKeypair(self: Service, keypair: KeypairDto) proc handleKeypair(self: Service, keypair: KeypairDto)
proc updateAccountsPositions(self: Service) proc updateAccountsPositions(self: Service)
proc importPartiallyOperableAccounts(self: Service, keyUid: string, password: string) proc importPartiallyOperableAccounts(self: Service, keyUid: string, password: string)
proc parseCurrencyValueByTokensKey*(self: Service, tokensKey: string, amountInt: UInt256): float64
proc fetchENSNamesForAddressesAsync(self: Service, addresses: seq[string], chainId: int)
# All slots defined in included files have to be forward declared # All slots defined in included files have to be forward declared
proc onAllTokensBuilt*(self: Service, response: string) {.slot.} proc onAllTokensBuilt*(self: Service, response: string) {.slot.}
proc onDerivedAddressesFetched*(self: Service, jsonString: string) {.slot.} proc onDerivedAddressesFetched*(self: Service, jsonString: string) {.slot.}
@ -66,7 +68,7 @@ QtObject:
proc onFetchChainIdForUrl*(self: Service, jsonString: string) {.slot.} proc onFetchChainIdForUrl*(self: Service, jsonString: string) {.slot.}
proc onNonProfileKeycardKeypairMigratedToApp*(self: Service, response: string) {.slot.} proc onNonProfileKeycardKeypairMigratedToApp*(self: Service, response: string) {.slot.}
proc tokenBalanceHistoryDataResolved*(self: Service, response: string) {.slot.} proc tokenBalanceHistoryDataResolved*(self: Service, response: string) {.slot.}
proc parseCurrencyValueByTokensKey*(self: Service, tokensKey: string, amountInt: UInt256): float64 proc onENSNamesFetched*(self: Service, response: string) {.slot.}
proc delete*(self: Service) = proc delete*(self: Service) =
self.closingApp = true self.closingApp = true

View File

@ -136,17 +136,20 @@ proc startWallet(self: Service) =
proc init*(self: Service) = proc init*(self: Service) =
try: try:
var addressesToGetENSName: seq[string] = @[]
let chainId = self.networkService.getAppNetwork().chainId let chainId = self.networkService.getAppNetwork().chainId
let woAccounts = getWatchOnlyAccountsFromDb() let woAccounts = getWatchOnlyAccountsFromDb()
for acc in woAccounts: for acc in woAccounts:
acc.ens = getEnsName(acc.address, chainId) addressesToGetENSName.add(acc.address)
self.storeWatchOnlyAccount(acc) self.storeWatchOnlyAccount(acc)
let keypairs = getKeypairsFromDb() let keypairs = getKeypairsFromDb()
for kp in keypairs: for kp in keypairs:
for acc in kp.accounts: for acc in kp.accounts:
acc.ens = getEnsName(acc.address, chainId) addressesToGetENSName.add(acc.address)
self.storeKeypair(kp) self.storeKeypair(kp)
self.fetchENSNamesForAddressesAsync(addressesToGetENSName, chainId)
let addresses = self.getWalletAddresses() let addresses = self.getWalletAddresses()
self.checkRecentHistory(addresses) self.checkRecentHistory(addresses)
self.startWallet() self.startWallet()
@ -195,8 +198,8 @@ proc addNewKeypairsAccountsToLocalStoreAndNotify(self: Service, notify: bool = t
break break
if found: if found:
continue continue
woAccDb.ens = getEnsName(woAccDb.address, chainId)
self.storeWatchOnlyAccount(woAccDb) self.storeWatchOnlyAccount(woAccDb)
self.fetchENSNamesForAddressesAsync(@[woAccDb.address], chainId)
self.buildAllTokens(@[woAccDb.address], store = true) self.buildAllTokens(@[woAccDb.address], store = true)
if notify: if notify:
self.events.emit(SIGNAL_WALLET_ACCOUNT_SAVED, AccountArgs(account: woAccDb)) self.events.emit(SIGNAL_WALLET_ACCOUNT_SAVED, AccountArgs(account: woAccDb))
@ -207,9 +210,9 @@ proc addNewKeypairsAccountsToLocalStoreAndNotify(self: Service, notify: bool = t
if localKp.isNil: if localKp.isNil:
self.storeKeypair(kpDb) self.storeKeypair(kpDb)
let addresses = kpDb.accounts.map(a => a.address) let addresses = kpDb.accounts.map(a => a.address)
self.fetchENSNamesForAddressesAsync(addresses, chainId)
self.buildAllTokens(addresses, store = true) self.buildAllTokens(addresses, store = true)
for acc in kpDb.accounts: for acc in kpDb.accounts:
acc.ens = getEnsName(acc.address, chainId)
if acc.isChat: if acc.isChat:
continue continue
if notify: if notify:
@ -223,8 +226,8 @@ proc addNewKeypairsAccountsToLocalStoreAndNotify(self: Service, notify: bool = t
break break
if found: if found:
continue continue
accDb.ens = getEnsName(accDb.address, chainId)
self.storeAccountToKeypair(accDb) self.storeAccountToKeypair(accDb)
self.fetchENSNamesForAddressesAsync(@[accDb.address], chainId)
if accDb.isChat: if accDb.isChat:
continue continue
self.buildAllTokens(@[accDb.address], store = true) self.buildAllTokens(@[accDb.address], store = true)
@ -279,19 +282,21 @@ proc updateAccountsPositions(self: Service) =
continue continue
localAcc.position = dbAcc.position localAcc.position = dbAcc.position
proc updateAccountInLocalStoreAndNotify(self: Service, address, name, colorId, emoji: string, operable: string = "", proc updateAccountInLocalStoreAndNotify(self: Service, address, name, colorId, emoji: string, ensName: string = "",
positionUpdated: Option[bool] = none(bool), notify: bool = true) = operable: string = "", positionUpdated: Option[bool] = none(bool), notify: bool = true) =
if address.len > 0: if address.len > 0:
var account = self.getAccountByAddress(address) var account = self.getAccountByAddress(address)
if account.isNil: if account.isNil:
return return
if name.len > 0 or colorId.len > 0 or emoji.len > 0 or operable.len > 0: if name.len > 0 or colorId.len > 0 or emoji.len > 0 or operable.len > 0 or ensName.len > 0:
if name.len > 0 and name != account.name: if name.len > 0 and name != account.name:
account.name = name account.name = name
if colorId.len > 0 and colorId != account.colorId: if colorId.len > 0 and colorId != account.colorId:
account.colorId = colorId account.colorId = colorId
if emoji.len > 0 and emoji != account.emoji: if emoji.len > 0 and emoji != account.emoji:
account.emoji = emoji account.emoji = emoji
if ensName.len > 0 and ensName != account.ens:
account.ens = ensName
if operable.len > 0 and operable != account.operable and if operable.len > 0 and operable != account.operable and
(operable == AccountNonOperable or operable == AccountPartiallyOperable or operable == AccountFullyOperable): (operable == AccountNonOperable or operable == AccountPartiallyOperable or operable == AccountFullyOperable):
account.operable = operable account.operable = operable
@ -445,7 +450,7 @@ proc makePartiallyOperableAccoutsFullyOperable(self: Service, password: string,
return return
let affectedAccounts = map(response.result.getElems(), x => x.getStr()) let affectedAccounts = map(response.result.getElems(), x => x.getStr())
for acc in affectedAccounts: for acc in affectedAccounts:
self.updateAccountInLocalStoreAndNotify(acc, name = "", colorId = "", emoji = "", operable = AccountFullyOperable) self.updateAccountInLocalStoreAndNotify(acc, name = "", colorId = "", emoji = "", ensName = "", operable = AccountFullyOperable)
except Exception as e: except Exception as e:
error "error: ", procName="makeSeedPhraseKeypairFullyOperable", errName=e.name, errDesription=e.msg error "error: ", procName="makeSeedPhraseKeypairFullyOperable", errName=e.name, errDesription=e.msg
@ -464,7 +469,7 @@ proc onNonProfileKeycardKeypairMigratedToApp*(self: Service, response: string) {
else: else:
kp.keycards = @[] kp.keycards = @[]
except Exception as e: except Exception as e:
error "error handilng migrated keycard response", errDesription=e.msg error "error handling migrated keycard response", errDesription=e.msg
self.events.emit(SIGNAL_ALL_KEYCARDS_DELETED, data) self.events.emit(SIGNAL_ALL_KEYCARDS_DELETED, data)
proc migrateNonProfileKeycardKeypairToAppAsync*(self: Service, keyUid, seedPhrase, password: string, doPasswordHashing: bool) = proc migrateNonProfileKeycardKeypairToAppAsync*(self: Service, keyUid, seedPhrase, password: string, doPasswordHashing: bool) =
@ -481,6 +486,29 @@ proc migrateNonProfileKeycardKeypairToAppAsync*(self: Service, keyUid, seedPhras
) )
self.threadpool.start(arg) self.threadpool.start(arg)
proc onENSNamesFetched*(self: Service, response: string) {.slot.} =
try:
let responseObj = response.parseJson
if responseObj{"error"}.kind != JNull and responseObj{"error"}.getStr != "":
raise newException(CatchableError, responseObj["error"].getStr)
for address, name in responseObj["result"].pairs:
let ensName = name.getStr
if ensName.len == 0:
continue
self.updateAccountInLocalStoreAndNotify(address, name = "", colorId = "", emoji = "", ensName)
except Exception as e:
error "error getting ENS names for accounts", errDesription=e.msg
proc fetchENSNamesForAddressesAsync(self: Service, addresses: seq[string], chainId: int) =
let arg = FetchENSNamesForAddressesTaskArg(
tptr: fetchENSNamesForAddressesTask,
vptr: cast[ByteAddress](self.vptr),
slot: "onENSNamesFetched",
addresses: addresses,
chainId: chainId
)
self.threadpool.start(arg)
proc getRandomMnemonic*(self: Service): string = proc getRandomMnemonic*(self: Service): string =
try: try:
let response = status_go_accounts.getRandomMnemonic() let response = status_go_accounts.getRandomMnemonic()
@ -621,7 +649,7 @@ proc moveAccountFinally*(self: Service, fromPosition: int, toPosition: int) =
updated = true updated = true
except Exception as e: except Exception as e:
error "error: ", procName="moveAccountFinally", errName=e.name, errDesription=e.msg error "error: ", procName="moveAccountFinally", errName=e.name, errDesription=e.msg
self.updateAccountInLocalStoreAndNotify(address = "", name = "", colorId = "", emoji = "", operable = "", some(updated)) self.updateAccountInLocalStoreAndNotify(address = "", name = "", colorId = "", emoji = "", ensName = "", operable = "", some(updated))
proc updateKeypairName*(self: Service, keyUid: string, name: string) = proc updateKeypairName*(self: Service, keyUid: string, name: string) =
try: try:
@ -719,7 +747,7 @@ proc handleWalletAccount(self: Service, account: WalletAccountDto, notify: bool
var localAcc = self.getAccountByAddress(account.address) var localAcc = self.getAccountByAddress(account.address)
if not localAcc.isNil: if not localAcc.isNil:
self.updateAccountInLocalStoreAndNotify(account.address, account.name, account.colorId, account.emoji, self.updateAccountInLocalStoreAndNotify(account.address, account.name, account.colorId, account.emoji,
account.operable, none(bool), notify) account.ens, account.operable, none(bool), notify)
else: else:
self.addNewKeypairsAccountsToLocalStoreAndNotify(notify) self.addNewKeypairsAccountsToLocalStoreAndNotify(notify)