taler-typescript-core

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

commit 56956b1740b188a1cc0efc354eec831c0fae76dc
parent 8f457f16b136898c268ad3897a8bea866801c239
Author: Florian Dold <florian@dold.me>
Date:   Tue, 16 Sep 2025 19:25:11 +0200

wallet-core: testing request to run fixups manually

Diffstat:
Mpackages/taler-util/src/types-taler-wallet.ts | 9+++++++++
Mpackages/taler-wallet-core/src/db.ts | 18+++++++++---------
Mpackages/taler-wallet-core/src/dev-experiments.ts | 1-
Mpackages/taler-wallet-core/src/wallet-api-types.ts | 9+++++++++
Mpackages/taler-wallet-core/src/wallet.ts | 24++++++++++++++++++++++++
Mpackages/taler-wallet-core/src/withdraw.ts | 2--
6 files changed, 51 insertions(+), 12 deletions(-)

diff --git a/packages/taler-util/src/types-taler-wallet.ts b/packages/taler-util/src/types-taler-wallet.ts @@ -3693,6 +3693,15 @@ export const codecForTestingGetDenomStatsRequest = .property("exchangeBaseUrl", codecForCanonBaseUrl()) .build("TestingGetDenomStatsRequest"); +export interface RunFixupRequest { + id: string; +} + +export const codecForRunFixupRequest = (): Codec<RunFixupRequest> => + buildCodecForObject<RunFixupRequest>() + .property("id", codecForString()) + .build("RunFixupRequest"); + export interface WithdrawalExchangeAccountDetails { /** * Payto URI to credit the exchange. diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts @@ -1801,15 +1801,6 @@ export interface WithdrawalGroupRecord { */ denomsSel?: DenomSelectionState; - /** - * UID of the denomination selection. - * - * Used for merging backups. - * - * FIXME: Should this not also include a timestamp for more logical merging? - */ - denomSelUid: string; - abortReason?: TalerErrorDetail; failReason?: TalerErrorDetail; } @@ -3671,6 +3662,9 @@ async function fixup20250915TopsBlunder( if (!exchRec) { continue; } + logger.info( + `have exchange ${exch} in update state ${exchRec.updateStatus}`, + ); exchRec.lastUpdate = undefined; exchRec.lastKeysEtag = undefined; switch (exchRec.updateStatus) { @@ -3691,13 +3685,19 @@ async function fixup20250915TopsBlunder( for (const exch of exchangeUrls) { const wgs = await tx.withdrawalGroups.indexes.byExchangeBaseUrl.getAll(exch); + logger.info( + `have ${wgs.length} withdrawal transactions that might need fixup`, + ); for (const wg of wgs) { + logger.info(`status ${wg.status}`); + logger.info(`denom sel ${j2s(wg.denomsSel)}`); if (wg.status !== WithdrawalGroupStatus.Done) { continue; } if (wg.denomsSel?.selectedDenoms.length != 0) { continue; } + logger.info(`updating withdrawal group status`); wg.status = WithdrawalGroupStatus.PendingQueryingStatus; await tx.withdrawalGroups.put(wg); } diff --git a/packages/taler-wallet-core/src/dev-experiments.ts b/packages/taler-wallet-core/src/dev-experiments.ts @@ -352,7 +352,6 @@ async function addFakeTx( } await wex.db.runAllStoresReadWriteTx({}, async (tx) => { await tx.withdrawalGroups.add({ - denomSelUid: encodeCrock(getRandomBytes(32)), reservePriv: reservePair.priv, reservePub: reservePair.pub, secretSeed, diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts @@ -141,6 +141,7 @@ import { RemoveGlobalCurrencyAuditorRequest, RemoveGlobalCurrencyExchangeRequest, RetryTransactionRequest, + RunFixupRequest, SetCoinSuspendedRequest, SetWalletDeviceIdRequest, SharePaymentRequest, @@ -317,6 +318,7 @@ export enum WalletApiOperation { TestingResetAllRetries = "testingResetAllRetries", TestingWaitExchangeWalletKyc = "testingWaitWalletKyc", TestingPlanMigrateExchangeBaseUrl = "testingPlanMigrateExchangeBaseUrl", + TestingRunFixup = "testingRunFixup", // Hints @@ -1382,6 +1384,12 @@ export type TestingGetDenomStatsOp = { response: TestingGetDenomStatsResponse; }; +export type TestingRunFixupOp = { + op: WalletApiOperation.TestingRunFixup; + request: RunFixupRequest; + response: EmptyObject; +}; + /** * Set a coin as (un-)suspended. * Suspended coins won't be used for payments. @@ -1510,6 +1518,7 @@ export type WalletOperations = { [WalletApiOperation.RemoveGlobalCurrencyExchange]: RemoveGlobalCurrencyExchangeOp; [WalletApiOperation.ListAssociatedRefreshes]: ListAssociatedRefreshesOp; [WalletApiOperation.TestingGetDenomStats]: TestingGetDenomStatsOp; + [WalletApiOperation.TestingRunFixup]: TestingRunFixupOp; [WalletApiOperation.TestingPing]: TestingPingOp; [WalletApiOperation.Shutdown]: ShutdownOp; [WalletApiOperation.PrepareBankIntegratedWithdrawal]: PrepareBankIntegratedWithdrawalOp; diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts @@ -108,6 +108,7 @@ import { RecoverStoredBackupRequest, RemoveGlobalCurrencyAuditorRequest, RemoveGlobalCurrencyExchangeRequest, + RunFixupRequest, ScopeType, SharePaymentRequest, SharePaymentResult, @@ -209,6 +210,7 @@ import { codecForRemoveGlobalCurrencyExchangeRequest, codecForResumeTransaction, codecForRetryTransactionRequest, + codecForRunFixupRequest, codecForSetCoinSuspendedRequest, codecForSetWalletDeviceIdRequest, codecForSharePaymentRequest, @@ -290,6 +292,7 @@ import { openTalerDatabase, timestampAbsoluteFromDb, timestampProtocolToDb, + walletDbFixups, } from "./db.js"; import { checkDepositGroup, @@ -1813,6 +1816,23 @@ export async function handleHintApplicationResumed( return {}; } +export async function handleTestingRunFixup( + wex: WalletExecutionContext, + req: RunFixupRequest, +): Promise<EmptyObject> { + for (const fixup of walletDbFixups) { + if (fixup.name != req.id) { + continue; + } + await wex.db.runAllStoresReadWriteTx({}, async (tx) => { + await fixup.fn(tx); + await rematerializeTransactions(wex, tx); + }); + return {}; + } + throw Error("fixup not found"); +} + async function handleGetVersion( wex: WalletExecutionContext, ): Promise<WalletCoreVersion> { @@ -1859,6 +1879,10 @@ const handlers: { [T in WalletApiOperation]: HandlerWithValidator<T> } = { codec: codecForEmptyObject(), handler: handleHintApplicationResumed, }, + [WalletApiOperation.TestingRunFixup]: { + codec: codecForRunFixupRequest(), + handler: handleTestingRunFixup, + }, [WalletApiOperation.AbortTransaction]: { codec: codecForAbortTransaction(), handler: handleAbortTransaction, diff --git a/packages/taler-wallet-core/src/withdraw.ts b/packages/taler-wallet-core/src/withdraw.ts @@ -3522,7 +3522,6 @@ export async function internalPrepareCreateWithdrawalGroup( } let initialDenomSel: DenomSelectionState | undefined; - const denomSelUid = encodeCrock(getRandomBytes(16)); if (amount !== undefined && exchangeBaseUrl !== undefined) { initialDenomSel = await getInitialDenomsSelection( @@ -3534,7 +3533,6 @@ export async function internalPrepareCreateWithdrawalGroup( } const withdrawalGroup: WithdrawalGroupRecord = { - denomSelUid, // next fields will be undefined if exchange or amount is not specified denomsSel: initialDenomSel, exchangeBaseUrl: exchangeBaseUrl,