Repository navigation
fix(assets-controller): revalidate quiet snap accounts and treat an empty balance map as a failure - #11070
Draft
rvelaz wants to merge 1 commit into
Conversation
…mpty balance map as a failure Snap accounts that are not pushing balance updates are re-checked after 90 s so a chain whose snap keeps failing is flagged unavailable instead of keeping a stale value. An empty balance map from the snap counts as a failed fetch. Includes the stale-balance tests (flagged unavailable, Retry asks the snap, recovery clears it).
This was referenced Oct 26, 2026
perf(bitcoin): scan new accounts with a gap of 5 and deepen only if used
MetaMask/internal-snaps#522
Draft
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
@metamask/assets-controllerExplanation
Bug
A non-EVM chain that starts failing after it had a balance keeps its cached amount for minutes, because a snap whose syncs fail simply stops pushing updates. And a snap that swallows a network error and returns
{}is treated as a confirmed (empty) result, so SOL never shows an error.How to reproduce
release/13.54.0(acf000d) withyarn build:dev, with this branch's@metamask/assets-controllerbuild innode_modules(locally we patched the 19.0.0 dist). Add extension PR 12 to see the UI. This PR is stacked on PR 10.tron-mainnet/solana-mainnet.infura.iocan reuse the HTTP/2 connection already open to another*.infura.iohost (in our runs the Solana snap usually opened it first). The reply is an empty 404 without CORS headers, so the snap seesFailed to fetch. We reproduced this on a test machine where every*.infura.ioname resolved to the same IP. It depends on the network path and may not reproduce on every network. In our runs we moved the shared connection between hosts on purpose: we dropped the test browser's sockets while briefly blocking the other Infura hosts, which "heals" one chain and breaks the others.--disable-http2give no coalescing, and all four balances are correct.Expected: within about 90 s of a chain going quiet (or at once for an empty map), the row shows "Balance unavailable" + Retry, and it clears after recovery.
Actual (before this change): TRX kept the cached 24.11 for about 7 minutes (fixes-v2 A-v2: 10:34:19 → 10:41:00), and SOL never showed an error (A-v2, failing from 10:30).
Without a browser:
SnapDataSource.test.ts›revalidation of subscribed accounts (v3)›flags a quiet, failing snap account unavailable after the revalidation window (TRX case)andan empty balance map for requested assets is a failure, not a confirmed balance (SOL case, v6).Summary
Two gaps remained after PR 10, and both let a stale or failed snap balance look current:
SnapDataSourcenow records when each subscribed snap account's balance was last confirmed (a successful fetch or a pushed update). Every 15 s it checks for accounts with nothing confirmed for 90 s and re-fetches them withforceUpdate. A failure enters the PR 10 error and backoff path, so the row says "Balance unavailable".{}fromgetAccountBalances. That is now recorded as a failed fetch (Snap returned no balances for the requested assets: N asset(s) requested), not stored as a confirmed result.Why
In Chrome, HTTP/2 connection coalescing across
*.infura.iocan send a snap's request over a connection opened for another Infura host. The reply is an empty 404 without CORS headers, so the snap seesFailed to fetch. With PR 10 alone, the error state appeared only when core itself fetched and the snap threw. In the EM v2 run, TRX took about 7 min to show "Balance unavailable" after its connection broke, because the tron snap stopped pushing and nothing in core fetched it again (the quiet-account case). The solana snap answered failed fetches with an empty map, which core stored as a confirmed result (the empty-map case). Healthy snaps push every 30–60 s, so a 90 s window does not re-fetch them.What changed
data-sources/SnapDataSource.ts:SNAP_BALANCE_REVALIDATE_AFTER_MS = 90_000,SNAP_BALANCE_REVALIDATE_CHECK_INTERVAL_MS = 15_000andSNAP_EMPTY_BALANCES_ERROR.revalidation?: { afterMs?, checkIntervalMs? } | falseoption.#lastConfirmedAtis set on subscribe, on a successful fetch and on a snap-pushed update.unsubscribeanddestroystop the watching and the timer.SnapDataSource.test.ts: a 'revalidation of subscribed accounts' describe with 6 tests:Validation
Checked locally: the test files changed in this PR were run with the parent's source (tests from this branch, every other file from the parent), then on this branch.
Unit tests that fail before and pass after (parent: PR 10)
SnapDataSource › ... › revalidation of subscribed accounts (v3) ›all 8:flags a quiet, failing snap account unavailable after the revalidation window (TRX case),an empty balance map for requested assets is a failure, not a confirmed balance (SOL case, v5)and(v6),flags a synced account unavailable when the snap reports its balance as stale, Retry asks the snap, and recovery clears it,does not ask again when the snap pushed balances recently,leaves failing accounts to their scheduled retries,runs on its own timer, and stops after unsubscribe,can be disabledFull run on this branch
jest --runInBand --forceExitinpackages/assets-controller: 49 suites, 1348 tests pass (PR 10: 1340).93f4402(621, 522 of them TS6307 notices caused by the no-references config).Manual A/B
A = Chrome with default HTTP/2 (reproduces the coalescing); B = Chrome with
--disable-http2(control, no coalescing). Every run used the same test wallet and a localyarn build:devof extension 13.54.0 (acf000d), with the snaps and assets-controller wired into node_modules by hand. "Unfixed 13.54.0" is that build with no fixes. The fixes-vN builds are cumulative: each one has every fix up to that pass, so an "after" number shows this PR together with the others in that build. Run names (A-v6, B-v7, ...) are our local test passes on those builds; times are CEST.Risks
getAccountBalancesper 90 s window, and only while it is subscribed and not already on the PR 10 backoff. Healthy snaps that push regularly get no extra calls.0) for every requested asset.Changelog (
packages/assets-controller/CHANGELOG.md, Unreleased → Fixed)References
Dependencies
Stale non-EVM balances series (Chrome HTTP/2 coalescing across
*.infura.io):Checklist