mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-android.git
synced 2026-04-21 23:48:00 +00:00
fix: prevent staking dashboard hang when exposure flag not cached
isPagedExposuresUsed() called storageCache.getEntry() which suspends forever if the entry doesn't exist. The flag is only written by ValidatorExposureUpdater (staking detail flow), so the dashboard would hang indefinitely waiting for it. Check cache first with isFullKeyInCache() and default to paged exposures when the flag is absent. Also remove debug log statements.
This commit is contained in:
-11
@@ -1,7 +1,5 @@
|
|||||||
package io.novafoundation.nova.common.data.memory
|
package io.novafoundation.nova.common.data.memory
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import io.novafoundation.nova.common.utils.LOG_TAG
|
|
||||||
import io.novafoundation.nova.common.utils.flowOfAll
|
import io.novafoundation.nova.common.utils.flowOfAll
|
||||||
import io.novafoundation.nova.common.utils.inBackground
|
import io.novafoundation.nova.common.utils.inBackground
|
||||||
import io.novafoundation.nova.common.utils.invokeOnCompletion
|
import io.novafoundation.nova.common.utils.invokeOnCompletion
|
||||||
@@ -75,17 +73,12 @@ internal class RealComputationalCache : ComputationalCache, CoroutineScope by Co
|
|||||||
val awaitable = mutex.withLock {
|
val awaitable = mutex.withLock {
|
||||||
val existing = memory[key]
|
val existing = memory[key]
|
||||||
if (existing != null && existing.aggregateScope.isActive) {
|
if (existing != null && existing.aggregateScope.isActive) {
|
||||||
Log.d(LOG_TAG, "Key $key requested - already present")
|
|
||||||
|
|
||||||
existing.dependents += scope
|
existing.dependents += scope
|
||||||
|
|
||||||
existing.awaitable
|
existing.awaitable
|
||||||
} else {
|
} else {
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
Log.d(LOG_TAG, "Key $key requested - stale (aggregateScope cancelled), recreating")
|
|
||||||
memory.remove(key)
|
memory.remove(key)
|
||||||
} else {
|
|
||||||
Log.d(LOG_TAG, "Key $key requested - creating new operation")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val aggregateScope = CoroutineScope(Dispatchers.Default)
|
val aggregateScope = CoroutineScope(Dispatchers.Default)
|
||||||
@@ -104,13 +97,9 @@ internal class RealComputationalCache : ComputationalCache, CoroutineScope by Co
|
|||||||
entry.dependents -= scope
|
entry.dependents -= scope
|
||||||
|
|
||||||
if (entry.dependents.isEmpty()) {
|
if (entry.dependents.isEmpty()) {
|
||||||
Log.d(this@RealComputationalCache.LOG_TAG, "Key $key - last scope cancelled")
|
|
||||||
|
|
||||||
memory.remove(key)
|
memory.remove(key)
|
||||||
|
|
||||||
entry.aggregateScope.cancel()
|
entry.aggregateScope.cancel()
|
||||||
} else {
|
|
||||||
Log.d(this@RealComputationalCache.LOG_TAG, "Key $key - scope cancelled, ${entry.dependents.size} remaining")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -156,7 +156,6 @@ class PezkuwiDashboardRepository(
|
|||||||
}
|
}
|
||||||
kycModule.storage("KycStatuses").query(accountId, binding = { decoded ->
|
kycModule.storage("KycStatuses").query(accountId, binding = { decoded ->
|
||||||
val enumName = decoded?.castToDictEnum()?.name
|
val enumName = decoded?.castToDictEnum()?.name
|
||||||
Log.d("PezkuwiDashboard", "KYC status raw enum: '$enumName' (decoded=$decoded)")
|
|
||||||
when (enumName) {
|
when (enumName) {
|
||||||
"PendingReferral" -> CitizenshipStatus.PENDING_REFERRAL
|
"PendingReferral" -> CitizenshipStatus.PENDING_REFERRAL
|
||||||
"ReferrerApproved" -> CitizenshipStatus.REFERRER_APPROVED
|
"ReferrerApproved" -> CitizenshipStatus.REFERRER_APPROVED
|
||||||
|
|||||||
-1
@@ -130,7 +130,6 @@ class RealStakingDashboardUpdateSystem(
|
|||||||
val stats = runCatching {
|
val stats = runCatching {
|
||||||
stakingStatsDataSource.fetchStakingStats(stakingAccounts, stakingChains)
|
stakingStatsDataSource.fetchStakingStats(stakingAccounts, stakingChains)
|
||||||
}.getOrElse {
|
}.getOrElse {
|
||||||
Log.d("StakingDashboardUpdateSystem", "Failed to fetch staking stats after retries", it)
|
|
||||||
emptyMap()
|
emptyMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
@@ -405,6 +405,16 @@ class StakingRepositoryImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun isPagedExposuresUsed(chainId: ChainId): Boolean {
|
private suspend fun isPagedExposuresUsed(chainId: ChainId): Boolean {
|
||||||
|
// Check if the flag is already in cache before calling getEntry, which suspends
|
||||||
|
// forever if the entry doesn't exist. The flag is written by ValidatorExposureUpdater
|
||||||
|
// which only runs in the staking detail flow, not the dashboard.
|
||||||
|
val isCached = storageCache.isFullKeyInCache(ValidatorExposureUpdater.STORAGE_KEY_PAGED_EXPOSURES, chainId)
|
||||||
|
if (!isCached) {
|
||||||
|
// Default to paged exposures (modern chains). If paged returns empty,
|
||||||
|
// getElectedValidatorsExposure will return an empty map gracefully.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
val isPagedExposuresValue = storageCache.getEntry(ValidatorExposureUpdater.STORAGE_KEY_PAGED_EXPOSURES, chainId)
|
val isPagedExposuresValue = storageCache.getEntry(ValidatorExposureUpdater.STORAGE_KEY_PAGED_EXPOSURES, chainId)
|
||||||
|
|
||||||
return ValidatorExposureUpdater.decodeIsPagedExposuresValue(isPagedExposuresValue.content)
|
return ValidatorExposureUpdater.decodeIsPagedExposuresValue(isPagedExposuresValue.content)
|
||||||
|
|||||||
-8
@@ -225,14 +225,6 @@ class RealStakingDashboardInteractor(
|
|||||||
noPriceStakingDashboard: NoPriceStakingDashboard,
|
noPriceStakingDashboard: NoPriceStakingDashboard,
|
||||||
assets: Map<FullChainAssetId, Asset>,
|
assets: Map<FullChainAssetId, Asset>,
|
||||||
): ExtendedLoadingState<StakingDashboard> {
|
): ExtendedLoadingState<StakingDashboard> {
|
||||||
Log.d(
|
|
||||||
"StakingDashboard",
|
|
||||||
"addPricesToDashboard: hasStake=${noPriceStakingDashboard.hasStake.size}, " +
|
|
||||||
"noStake=${noPriceStakingDashboard.noStake.size}, " +
|
|
||||||
"notYetResolved=${noPriceStakingDashboard.notYetResolved.size}, " +
|
|
||||||
"assets=${assets.size}"
|
|
||||||
)
|
|
||||||
|
|
||||||
val hasStakeOptions = noPriceStakingDashboard.hasStake.mapNotNull { addPriceToHasStakeItem(it, assets) }
|
val hasStakeOptions = noPriceStakingDashboard.hasStake.mapNotNull { addPriceToHasStakeItem(it, assets) }
|
||||||
val noStakeOptions = noPriceStakingDashboard.noStake.mapNotNull { addAssetInfoToNoStakeItem(it, assets) }
|
val noStakeOptions = noPriceStakingDashboard.noStake.mapNotNull { addAssetInfoToNoStakeItem(it, assets) }
|
||||||
val notYetResolvedOptions = noPriceStakingDashboard.notYetResolved.mapNotNull { addAssetInfoToNotYetResolvedItem(it, assets) }
|
val notYetResolvedOptions = noPriceStakingDashboard.notYetResolved.mapNotNull { addAssetInfoToNotYetResolvedItem(it, assets) }
|
||||||
|
|||||||
Reference in New Issue
Block a user