A balance refresh in flight during a network switch writes the previous network's balances onto the new one #577

Closed
opened 2026-10-19 02:51:19 +02:00 by clawbot · 3 comments
Collaborator

Seen by the review of #572, from reading the code.

Where

doRefreshAndRender() in src/popup/index.js and backgroundRefresh() in src/background/index.js. Each starts a balance refresh with the network's endpoints and wallets as they are, and when the requests return writes the balances into the same address records and saves.

What happens

A network switch (applyChainSwitchFields() in src/shared/chainSwitchFields.js) clears every address's balances while a refresh for the previous network may still be in flight. When that refresh returns, it writes the previous network's balances back onto the addresses, now shown under the new network, and records the refresh as done, so the next refresh on the new network waits its normal interval.

What should happen

applyChainSwitchFields() clears the balances on a switch "so stale data from the previous chain is never displayed". A refresh that returns after the network changed should be dropped, and the new network refreshed.

Severity: minor

Definition of done

  • A balance refresh started before a network switch writes nothing when it returns after the switch, in the popup and in the background.
  • A test holds a refresh open across a switch and checks the new network's addresses show no balance from the old one.

Model: opus-5-5

Seen by the review of https://git.eeqj.de/sneak/AutistMask/pulls/572, from reading the code. ## Where `doRefreshAndRender()` in `src/popup/index.js` and `backgroundRefresh()` in `src/background/index.js`. Each starts a balance refresh with the network's endpoints and wallets as they are, and when the requests return writes the balances into the same address records and saves. ## What happens A network switch (`applyChainSwitchFields()` in `src/shared/chainSwitchFields.js`) clears every address's balances while a refresh for the previous network may still be in flight. When that refresh returns, it writes the previous network's balances back onto the addresses, now shown under the new network, and records the refresh as done, so the next refresh on the new network waits its normal interval. ## What should happen `applyChainSwitchFields()` clears the balances on a switch "so stale data from the previous chain is never displayed". A refresh that returns after the network changed should be dropped, and the new network refreshed. Severity: minor ## Definition of done - [ ] A balance refresh started before a network switch writes nothing when it returns after the switch, in the popup and in the background. - [ ] A test holds a refresh open across a switch and checks the new network's addresses show no balance from the old one. Model: opus-5-5
clawbot self-assigned this 2026-10-19 02:51:19 +02:00
Author
Collaborator

Plan: one PR to next. Both refreshes note the network they started on. When their requests return, each writes the balances only if that network is still the active one: the popup's doRefreshAndRender() (src/popup/index.js) against state.networkId, the background's backgroundRefresh() (src/background/index.js) against the fresh record inside updateState(). Otherwise the results are dropped, lastBalanceRefresh is not recorded, and the new network is refreshed on the next tick. Since refreshBalances() writes into the address records it is given, the popup refreshes into records it alone holds and copies the results onto the live ones only after that check, so nothing from the old network can land on them. Jest tests that hold a refresh open across a switch, in the popup and in the background, each failing on next.

Model: opus-5-5

Plan: one PR to `next`. Both refreshes note the network they started on. When their requests return, each writes the balances only if that network is still the active one: the popup's `doRefreshAndRender()` (`src/popup/index.js`) against `state.networkId`, the background's `backgroundRefresh()` (`src/background/index.js`) against the fresh record inside `updateState()`. Otherwise the results are dropped, `lastBalanceRefresh` is not recorded, and the new network is refreshed on the next tick. Since `refreshBalances()` writes into the address records it is given, the popup refreshes into records it alone holds and copies the results onto the live ones only after that check, so nothing from the old network can land on them. Jest tests that hold a refresh open across a switch, in the popup and in the background, each failing on `next`. Model: opus-5-5
Author
Collaborator

Built in #648, as planned above. Both refreshes write their balances only if the network they started on is still the active one. The popup refreshes a copy of its wallets, so nothing reaches its own address records before that check.

Not covered: a switch the background makes (a site's request the user approved) does not change an open popup's network, so the popup's check does not see that switch.

Model: opus-5-5

Built in https://git.eeqj.de/sneak/AutistMask/pulls/648, as planned above. Both refreshes write their balances only if the network they started on is still the active one. The popup refreshes a copy of its wallets, so nothing reaches its own address records before that check. Not covered: a switch the background makes (a site's request the user approved) does not change an open popup's network, so the popup's check does not see that switch. Model: opus-5-5
Author
Collaborator

Plan, extended before review: an open popup does not see a switch the background makes (after the user approves a site's request), so its own state.networkId is not enough. The popup also checks the network of the stored record when it writes its refresh, inside its save under the lock from #644, and drops the refresh if that network differs from the one the refresh started on.

Model: opus-5-5

Plan, extended before review: an open popup does not see a switch the background makes (after the user approves a site's request), so its own `state.networkId` is not enough. The popup also checks the network of the stored record when it writes its refresh, inside its save under the lock from https://git.eeqj.de/sneak/AutistMask/pulls/644, and drops the refresh if that network differs from the one the refresh started on. Model: opus-5-5
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/AutistMask#577