mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-android.git
synced 2026-07-22 18:25:50 +00:00
fix: isolate per-chain/per-asset failures in ChainSyncService.syncUp()
A single malformed or not-yet-understood remote chain/asset entry used to
abort the whole sync via a plain .map{} - chainDao.applyDiff() never even
gets called, so a brand new install (empty local DB) ends up with zero
cached chains forever, i.e. a completely empty tokens list, until the
remote data or the app's parsing code changes. This is exactly what
happened in production: master's config received a batch of upstream
changes the still-live app version couldn't parse, and every fresh install
got stuck with a blank list while existing installs (which already had a
populated local DB from a prior successful sync) were unaffected.
Mirrors the same mapListNotNull + runCatching pattern already used on the
read side (ChainRegistry.currentChains) - one bad chain, or one bad asset
within an otherwise-fine chain, is now logged and skipped instead of taking
the rest of the sync down with it.
This commit is contained in:
+25
-9
@@ -57,17 +57,33 @@ class ChainSyncService(
|
||||
return@withContext
|
||||
}
|
||||
|
||||
val newChains = remoteChains.map { mapRemoteChainToLocal(it, oldChainsById[it.chainId], source = ChainLocal.Source.DEFAULT, gson) }
|
||||
val newAssets = remoteChains.flatMap { chain ->
|
||||
chain.assets.map {
|
||||
val fullAssetId = FullAssetIdLocal(chain.chainId, it.assetId)
|
||||
val oldAsset = associatedOldAssets[fullAssetId]
|
||||
mapRemoteAssetToLocal(chain, it, gson, oldAsset?.enabled ?: ENABLED_DEFAULT_BOOL)
|
||||
// One malformed/incompatible chain (a new field the app's mapper doesn't understand yet, a bad
|
||||
// publish, etc.) must not take down sync for every other chain - a plain .map{} here means a single
|
||||
// throwing chain aborts before chainDao.applyDiff() is ever called, leaving a brand new install with
|
||||
// zero locally-cached chains forever (a completely empty tokens list), since nothing else in this
|
||||
// function ever gets a chance to run. Isolate failures per chain, and per asset within a chain that
|
||||
// otherwise mapped fine, instead.
|
||||
val remoteChainsWithLocal = remoteChains.mapNotNull { chainRemote ->
|
||||
runCatching { chainRemote to mapRemoteChainToLocal(chainRemote, oldChainsById[chainRemote.chainId], source = ChainLocal.Source.DEFAULT, gson) }
|
||||
.onFailure { Log.e(LOG_TAG, "Failed to map remote chain ${chainRemote.chainId} (${chainRemote.name}), skipping it for this sync cycle", it) }
|
||||
.getOrNull()
|
||||
}
|
||||
|
||||
val newChains = remoteChainsWithLocal.map { (_, chainLocal) -> chainLocal }
|
||||
val newAssets = remoteChainsWithLocal.flatMap { (chain, _) ->
|
||||
chain.assets.mapNotNull { assetRemote ->
|
||||
runCatching {
|
||||
val fullAssetId = FullAssetIdLocal(chain.chainId, assetRemote.assetId)
|
||||
val oldAsset = associatedOldAssets[fullAssetId]
|
||||
mapRemoteAssetToLocal(chain, assetRemote, gson, oldAsset?.enabled ?: ENABLED_DEFAULT_BOOL)
|
||||
}.onFailure {
|
||||
Log.e(LOG_TAG, "Failed to map asset ${assetRemote.assetId} (${assetRemote.symbol}) on chain ${chain.chainId}, skipping it", it)
|
||||
}.getOrNull()
|
||||
}
|
||||
}
|
||||
val newNodes = remoteChains.flatMap(::mapRemoteNodesToLocal)
|
||||
val newExplorers = remoteChains.flatMap(::mapRemoteExplorersToLocal)
|
||||
val newExternalApis = remoteChains.flatMap(::mapExternalApisToLocal)
|
||||
val newNodes = remoteChainsWithLocal.flatMap { (chain, _) -> mapRemoteNodesToLocal(chain) }
|
||||
val newExplorers = remoteChainsWithLocal.flatMap { (chain, _) -> mapRemoteExplorersToLocal(chain) }
|
||||
val newExternalApis = remoteChainsWithLocal.flatMap { (chain, _) -> mapExternalApisToLocal(chain) }
|
||||
val newNodeSelectionPreferences = nodeSelectionPreferencesFor(newChains, oldNodeSelectionPreferences)
|
||||
|
||||
val chainsDiff = CollectionDiffer.findDiff(newChains, oldChains, forceUseNewItems = false)
|
||||
|
||||
Reference in New Issue
Block a user