revert: NativeAssetBalance back to raw subscribe(key), typed DSL made it worse

CI proved the typed remoteStorage.subscribe DSL swap (previous commit)
was not a fix - it was a regression. All 8 assets across all 3 Pezkuwi
chains failed to sync in the follow-up test run (vs just HEZ-on-Asset-Hub
before), and the logs showed what looks like storage keys meant for
Pezkuwi Asset Hub's Assets pallet being sent to the Pezkuwi relay chain's
connection instead - some kind of cross-chain contamination introduced
by the DSL's interaction with the shared connection, not understood yet.

Reverting to the raw subscriptionBuilder.subscribe(key) form restores
the prior, narrower state: 5 of 6 assets on Pezkuwi Asset Hub sync fine,
HEZ specifically does not, and every other chain is unaffected. The
underlying HEZ bug is still open - this just stops the attempted fix
from actively making things worse while it's investigated further.
This commit is contained in:
2026-07-09 13:32:17 -07:00
parent 593fedcdd4
commit ae8acb9d12
@@ -1,7 +1,6 @@
package io.novafoundation.nova.feature_wallet_impl.data.network.blockchain.assets.balances.utility
import android.util.Log
import io.novafoundation.nova.common.data.network.runtime.binding.AccountInfo
import io.novafoundation.nova.common.data.network.runtime.binding.bindList
import io.novafoundation.nova.common.data.network.runtime.binding.bindNumber
import io.novafoundation.nova.common.data.network.runtime.binding.castToDictEnum
@@ -18,6 +17,7 @@ import io.novafoundation.nova.core_db.dao.LockDao
import io.novafoundation.nova.core_db.model.BalanceHoldLocal
import io.novafoundation.nova.feature_account_api.domain.model.MetaAccount
import io.novafoundation.nova.feature_wallet_api.data.cache.AssetCache
import io.novafoundation.nova.feature_wallet_api.data.cache.bindAccountInfoOrDefault
import io.novafoundation.nova.feature_wallet_api.data.cache.updateAsset
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.balances.AssetBalance
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.balances.BalanceSyncUpdate
@@ -155,13 +155,13 @@ class NativeAssetBalance(
// the caller, FullSyncPaymentUpdater.syncAsset(), wraps this whole call in a single retryWhen boundary meant
// to catch and retry exactly these failures. Swallowing here would make that retry boundary never trigger.
//
// Uses the typed remoteStorage.subscribe { metadata.system.account... } DSL (same as this class's own
// subscribeAccountBalanceUpdatePoint() and PooledBalanceUpdater/BalanceLocksUpdater) instead of a raw
// subscriptionBuilder.subscribe(key) call: on chains with several other assets/updaters already sharing
// the same SharedRequestsBuilder (e.g. Pezkuwi Asset Hub's 5 statemine assets + nomination-pools updater),
// the raw form's System.Account subscription was silently never reaching the wire - no exception, no data,
// ever - while every other asset on the same chain synced fine. The typed DSL is what every other caller
// on a busy shared connection already uses successfully.
// NOTE (2026-07-09): a prior attempt switched this to the typed remoteStorage.subscribe { metadata.system
// .account... } DSL, on the theory that it would fix HEZ silently never syncing on Pezkuwi Asset Hub (see
// git history). That attempt made things categorically worse - all assets across all 3 Pezkuwi chains
// stopped syncing, with logs showing what looked like cross-chain key contamination on the shared
// connection. Reverted back to the raw subscriptionBuilder.subscribe(key) form here, which is not broken
// for any OTHER native asset on any OTHER chain - only Pezkuwi Asset Hub's HEZ specifically. That narrower
// bug is still open; do not re-attempt the DSL swap without first understanding why it caused contamination.
override suspend fun startSyncingBalance(
chain: Chain,
chainAsset: Chain.Asset,
@@ -169,18 +169,21 @@ class NativeAssetBalance(
accountId: AccountId,
subscriptionBuilder: SharedRequestsBuilder
): Flow<BalanceSyncUpdate> {
return remoteStorage.subscribe(chain.id, subscriptionBuilder) {
metadata.system.account.observeWithRaw(accountId)
}.map { change ->
val accountInfo = change.value ?: AccountInfo.empty()
val assetChanged = assetCache.updateAsset(metaAccount.id, chain.utilityAsset, accountInfo)
val runtime = chainRegistry.getRuntime(chain.id)
if (assetChanged) {
BalanceSyncUpdate.CauseFetchable(change.at!!)
} else {
BalanceSyncUpdate.NoCause
val key = runtime.metadata.system().storage("Account").storageKey(runtime, accountId)
return subscriptionBuilder.subscribe(key)
.map { change ->
val accountInfo = bindAccountInfoOrDefault(change.value, runtime)
val assetChanged = assetCache.updateAsset(metaAccount.id, chain.utilityAsset, accountInfo)
if (assetChanged) {
BalanceSyncUpdate.CauseFetchable(change.block)
} else {
BalanceSyncUpdate.NoCause
}
}
}
}
private fun bindBalanceHolds(dynamicInstance: Any?): List<BlockchainHold>? {