taler-typescript-core

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

commit 95f6b5cad01ef09f152fb5771c151e5d263866bf
parent c73a73e3471c37e59d63f4fd429e9f4589685003
Author: Florian Dold <dold@taler.net>
Date:   Sun,  9 Aug 2026 15:39:08 +0200

wallet-core: migrate legacy exchange retry counters

Diffstat:
Mpackages/taler-wallet-core/src/db-converter.test.ts | 34++++++++++++++++++++++++++++++++++
Mpackages/taler-wallet-core/src/db-converter.ts | 5++++-
2 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/packages/taler-wallet-core/src/db-converter.test.ts b/packages/taler-wallet-core/src/db-converter.test.ts @@ -104,6 +104,40 @@ test("converter: sqlite to IndexedDB (reverse direction)", async () => { await dst.close(); }); +test("converter: discards the legacy exchange update retry counter", async () => { + // Wallets written before exchange update retries were moved to + // operation_retries still retain this field in the IndexedDB record. The + // native schema deliberately has no corresponding column. + const src = await makeIdbRunner(); + await src.runReadWriteTx(async (tx) => { + await tx.upsertExchange({ + baseUrl: "https://exchange.example.com/", + detailsPointer: undefined, + entryStatus: ExchangeEntryDbRecordStatus.Used, + updateStatus: ExchangeEntryDbUpdateStatus.Ready, + tosCurrentEtag: undefined, + tosAcceptedEtag: undefined, + tosAcceptedTimestamp: undefined, + lastUpdate: undefined, + nextUpdateStamp: timestampPreciseToDb(TalerPreciseTimestamp.now()), + lastKeysEtag: undefined, + nextRefreshCheckStamp: timestampPreciseToDb(TalerPreciseTimestamp.now()), + updateRetryCounter: 8, + } as any); + }); + + const dst = await makeSqliteRunner(); + await convertWalletDb(src, dst); + const exchange = await dst.runReadWriteTx((tx) => + tx.getExchange("https://exchange.example.com/"), + ); + assert.ok(exchange); + assert.ok(!("updateRetryCounter" in exchange)); + + await src.close(); + await dst.close(); +}); + test("converter: reserve rows sharing a public key collapse into one", async () => { // What an IndexedDB wallet that ever received a peer payment looks like: // the merge reserve stored once by the exchange entry that points at it, diff --git a/packages/taler-wallet-core/src/db-converter.ts b/packages/taler-wallet-core/src/db-converter.ts @@ -84,6 +84,8 @@ const stripId = (rec: unknown): unknown => { * mistaken for legacy junk without a human putting its name here. */ const LEGACY_FIELDS: Record<string, string[]> = { + // Removed when exchange update retry state moved to operation_retries. + exchanges: ["updateRetryCounter"], // Removed 2024-06-13 ("remove coinAllocationId, simplify coin history"). coins: ["spendAllocation"], // Dropped when denomination records were restructured; nothing reads it. @@ -250,7 +252,8 @@ const COPY_PLAN: CopyStep[][] = [ step( "exchanges", (tx) => tx.getExchanges(), - (tx, r) => tx.upsertExchange(r), + (tx, r) => tx.upsertExchange(stripLegacy("exchanges")!(r) as any), + stripLegacy("exchanges"), ), ], [