taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 857a6824ba894dc95c172d5a63ba9e154263ae1e
parent 1a7a4325775d6b2ee4a0f1762733a1e7b288c1f0
Author: Florian Dold <dold@taler.net>
Date:   Sun, 19 Jul 2026 17:50:23 +0200

wallet: re-run fixups after importing a database, before rematerialising

Clearing the fixup log only schedules repairs for the next open.  An
imported pre-fixup backup crashed getTransactions until restart.

Diffstat:
Mpackages/taler-wallet-core/src/requests.ts | 21+++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/packages/taler-wallet-core/src/requests.ts b/packages/taler-wallet-core/src/requests.ts @@ -278,6 +278,7 @@ import { } from "./db-common.js"; import { CoinSourceType, + applyFixups, clearDatabase, exportDb, importDb, @@ -1602,14 +1603,30 @@ async function handleImportDb( ): Promise<EmptyObject> { // FIXME: This should atomically re-materialize transactions! await importDb(wex.db.idbHandle(), req.dump); + + // Clear the fixup log: the records that just arrived may predate any of + // the fixups, whatever this database had applied before the import. They + // are idempotent, so re-running them is safe. await wex.runLegacyWalletDbTx(async (tx) => { - await rematerializeTransactions(wex, tx.wtx); - // Clear fixups. Okay since they are idempotent. const fixups = await tx.fixups.getAll(); for (const f of fixups) { await tx.fixups.delete(f.fixupName); } }); + + // Then actually re-run them. Clearing the log alone only schedules the + // repairs for the next time the database is opened, which for a running + // wallet is never: every query until the next restart would see the + // imported records unrepaired. A backup from before the status-enum digit + // fix, for instance, imported cleanly and then crashed getTransactions on + // an operationStatus no enum member matched. + await applyFixups(wex.db); + + // Materialise the transaction view last, so it is built from repaired + // records rather than from what the import happened to contain. + await wex.runWalletDbTx(async (tx) => { + await rematerializeTransactions(wex, tx); + }); return {}; }