mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-android.git
synced 2026-07-22 17:15:48 +00:00
fix: retry Tron balance polling on failure instead of permanently dying
Real user on a fresh install reported TRX and USDT-TRC20 never appearing anywhere in the Tokens list (not "zero balance", genuinely absent - including from the multi-chain USDT chain picker). Traced the full pipeline; every layer up to and including TypeBasedAssetSourceRegistry, ChainRegistry, address derivation, and TronGridApi wiring was already correct. Root cause: pollingBalanceFlow() had no retry around fetch() - any single transient failure (DNS hiccup, timeout, momentary connectivity loss during app cold start) threw out of the `while(true)` loop, killing the flow permanently. The collector (FullSyncPaymentUpdater.syncAsset()) only logs and gives up on failure, it doesn't resubscribe. Since the asset's first balance write never happens, AssetCache never inserts a DB row for it, and every UI surface (main list, multi-chain picker, search) reads exclusively via an INNER JOIN that requires that row to exist - so the asset is invisible everywhere, permanently, with zero user-visible error. Swallow fetch() failures and retry on the next interval instead of letting them escape the loop - one bad poll no longer blackholes the asset for the rest of the app session. Also fixes a related but separate gap found while tracing this: RealSecretsMetaAccount.multiChainEncryptionIn() had no isTronBased branch (only isEthereumBased), unlike DefaultMetaAccount's hasAccountIn/accountIdIn which already handle Tron correctly. This didn't cause the missing-tokens bug, but would have broken "export account" (JSON key backup) for Tron - fixed by routing Tron through MultiChainEncryption.Ethereum, matching what RealTronTransactionService already does for actual transaction signing (same secp256k1 keypair).
This commit is contained in:
+5
-1
@@ -49,7 +49,9 @@ class RealSecretsMetaAccount(
|
||||
hasChainAccountIn(chain.id) -> {
|
||||
val cryptoType = chainAccounts.getValue(chain.id).cryptoType ?: return null
|
||||
|
||||
if (chain.isEthereumBased) {
|
||||
// Tron reuses the same secp256k1 keypair/signing as Ethereum - see
|
||||
// RealTronTransactionService's use of Signer.sign(MultiChainEncryption.Ethereum, ...).
|
||||
if (chain.isEthereumBased || chain.isTronBased) {
|
||||
MultiChainEncryption.Ethereum
|
||||
} else {
|
||||
MultiChainEncryption.substrateFrom(cryptoType)
|
||||
@@ -58,6 +60,8 @@ class RealSecretsMetaAccount(
|
||||
|
||||
chain.isEthereumBased -> MultiChainEncryption.Ethereum
|
||||
|
||||
chain.isTronBased -> MultiChainEncryption.Ethereum
|
||||
|
||||
else -> substrateCryptoType?.let(MultiChainEncryption.Companion::substrateFrom)
|
||||
}
|
||||
}
|
||||
|
||||
+13
-2
@@ -1,17 +1,26 @@
|
||||
package io.novafoundation.nova.feature_wallet_impl.data.network.blockchain.assets.balances.tronNative
|
||||
|
||||
import android.util.Log
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
private const val TRON_BALANCE_POLLING_INTERVAL_MS = 30_000L
|
||||
private const val LOG_TAG = "TronBalancePolling"
|
||||
|
||||
/**
|
||||
* TronGrid is a plain REST API with no push/subscription mechanism (unlike Ethereum nodes, which expose a
|
||||
* `newHeads`-style websocket subscription EVM balance sync piggybacks on). So balance updates for Tron-based
|
||||
* assets are polled instead of pushed: fetch immediately, then re-fetch on an interval, only emitting when the
|
||||
* balance actually changed.
|
||||
*
|
||||
* A failed fetch() must not escape this loop: any uncaught exception here cancels the whole flow permanently
|
||||
* (the collector - FullSyncPaymentUpdater - only logs and gives up, it doesn't resubscribe), which meant a
|
||||
* single transient failure (DNS hiccup, timeout, momentary connectivity loss during app cold start) could
|
||||
* silently and permanently blackhole a Tron asset - no balance write ever happens, so it never even gets a row
|
||||
* in the local DB and disappears from every UI surface with no visible error. Swallow and retry next interval
|
||||
* instead.
|
||||
*/
|
||||
internal fun pollingBalanceFlow(
|
||||
intervalMs: Long = TRON_BALANCE_POLLING_INTERVAL_MS,
|
||||
@@ -20,9 +29,11 @@ internal fun pollingBalanceFlow(
|
||||
var lastEmitted: Balance? = null
|
||||
|
||||
while (true) {
|
||||
val latest = fetch()
|
||||
val latest = runCatching { fetch() }
|
||||
.onFailure { Log.e(LOG_TAG, "Tron balance fetch failed, will retry in ${intervalMs}ms", it) }
|
||||
.getOrNull()
|
||||
|
||||
if (latest != lastEmitted) {
|
||||
if (latest != null && latest != lastEmitted) {
|
||||
lastEmitted = latest
|
||||
emit(latest)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user