View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0011952 | Taler | wallet-core | public | 2026-11-05 08:59 | 2026-11-05 08:59 |
| Reporter | bot-codex-florian-dold [agent] | Assigned To | Resolution deadline | ||
| Implementer | Reviewer | ||||
| Release signed by | Deployed by | ||||
| Verifier | Communicator | CM_7 | |||
| Data protection authority notification required | No | ||||
| CSIRT notification required | No | ||||
| Estimated effort (hours) | Actual effort (hours) | 0 | |||
| Fast-track | No | ||||
| Work package | none | ||||
| Priority | normal | Severity | minor | Reproducibility | have not tried |
| Status | new | Resolution | open | ||
| Summary | 0011952: wallet-core: bound refresh-cost work slices and coalesce validation-triggered recomputation | ||||
| Description | Bulk denomination validation repeatedly invalidates and recomputes the wallet-wide refresh-cost report, creating substantial background work and redundant frontend reloads. The existing chunking also does not bound the cost of an individual synchronous step. Evidence from an Android log using wallet-core 1.6.49, commit 9b08843c54a93d83b2df70cad9d25093b85720e1, with SQLite, observability events, and TRACE logging enabled: - A denomination-validation task takes 17.685 seconds. The captured portion includes 770 completed isValidDenom calls; the log begins after validation has already started. - During the initial burst, 11 consecutive refresh-balance runs each take 1.129-1.150 seconds. - The capture contains 19 balance-change notifications with hintTransactionId refresh-balance. Android reloads balances on these notifications, while the actual getBalances requests usually take only 2-3 ms. - Validation completes by scheduling auto-refresh for the staging exchange. Its master-key replacement is a plausible source of new denominations to verify, but the capture does not establish exactly why those denominations were unverified. Mechanism: validateDenoms writes verification results in batches of 70. upsertDenomination invalidates the persisted refresh-balance generation; runWalletDbTx then starts refresh-balance. That task loads a global snapshot and computes annual refresh bounds. Publication can notify again because generation invalidation made the previous visible report appear as checking, even if the computed report is otherwise unchanged. computeAnnualRefreshBoundAsync checks its 8 ms / 32-step budget only after steps.next() returns. A generator step can perform candidate filtering, sorting, output selection, and a further candidate scan, all synchronously. The expensive inner work therefore has no corresponding hard slice bound. Awaiting already-resolved in-memory lookups also does not necessarily service native I/O. The projection itself runs outside the database transaction; this issue should not be described as a database lock held for the full computation. Reported durations are elapsed time, not CPU measurements. In particular, the 17.199-second refresh-balance outlier spans the app going into the background and should not be treated as 17 seconds of CPU work. | ||||
| Steps To Reproduce | Use a wallet containing holdings at multiple exchanges and a large set of unverified denominations at one exchange. Run bulk validation while recording refresh-balance scheduling, snapshot/projection durations, publication, and balance notifications. Also benchmark annual-bound computation using enough candidate denominations to expose a costly single generator step, measuring the longest uninterrupted synchronous slice rather than only total task duration. Run the latency checks on Qtart with the runtime fairness issue fixed as well, to separate the cost of the calculation from event-loop starvation. | ||||
| Additional Information | Related runtime defect: https://bugs.taler.net/n/11951 Suggested scope and acceptance criteria: - Introduce a shared cooperative work-budget/yield mechanism with a meaningful host-I/O fairness contract, and instrument maximum uninterrupted slice duration. - Split or reduce expensive inner steps; avoid repeated full candidate filtering/sorting where inputs can be prepared or cached safely. - Coalesce rapid validation-batch invalidations and avoid repeatedly rebuilding unrelated scopes. Preserve prompt reporting of actual monetary balance changes and correctness when denomination validity changes. - Keep generation checks that prevent stale snapshots from being published, and ensure a final recomputation occurs after the last invalidation. Avoid unbounded debounce during sustained changes. - Demonstrate substantially fewer global projections and redundant reloads during a large validation batch, with correct final report contents and bounded foreground latency. Relevant files under packages/taler-wallet-core/src: denominations.ts (denomBatchSize / validateDenoms), db/shared.ts (refresh-balance invalidation), wallet.ts (runWalletDbTx), refreshBalance.ts (snapshot, computation and publication), autoRefresh.ts (annualRefreshBoundSteps / computeAnnualRefreshBoundAsync), autoRefreshBalance.ts. This is computation and invalidation work; interactive scheduling policy is tracked separately. | ||||
| Tags | No tags attached. | ||||
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2026-11-05 08:59 | bot-codex-florian-dold | New Issue |