From 0d69feb8057b6b812879ff38f1b3b85712817d94 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Mon, 25 Mar 2024 20:53:58 +0100 Subject: wallet-core: re-denomination of refresh groups --- packages/taler-wallet-core/src/refresh.ts | 73 +++++++++++++++++++++++++++--- packages/taler-wallet-core/src/withdraw.ts | 2 +- 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/packages/taler-wallet-core/src/refresh.ts b/packages/taler-wallet-core/src/refresh.ts index 7bf231870..a92b3baf1 100644 --- a/packages/taler-wallet-core/src/refresh.ts +++ b/packages/taler-wallet-core/src/refresh.ts @@ -60,7 +60,9 @@ import { } from "@gnu-taler/taler-util"; import { readSuccessResponseJsonOrThrow, + readTalerErrorResponse, readUnexpectedResponseDetails, + throwUnexpectedRequestError, } from "@gnu-taler/taler-util/http"; import { constructTaskIdentifier, @@ -103,7 +105,10 @@ import { getDenomInfo, WalletExecutionContext, } from "./wallet.js"; -import { getCandidateWithdrawalDenomsTx } from "./withdraw.js"; +import { + getCandidateWithdrawalDenomsTx, + updateWithdrawalDenoms, +} from "./withdraw.js"; const logger = new Logger("refresh.ts"); @@ -499,6 +504,8 @@ async function refreshMelt( refreshGroupId: string, coinIndex: number, ): Promise { + const ctx = new RefreshTransactionContext(wex, refreshGroupId); + const transactionId = ctx.transactionId; const d = await wex.db.runReadWriteTx( ["refreshGroups", "refreshSessions", "coins", "denominations"], async (tx) => { @@ -618,11 +625,6 @@ async function refreshMelt( }, ); - const transactionId = constructTransactionIdentifier({ - tag: TransactionType.Refresh, - refreshGroupId, - }); - if (resp.status === HttpStatusCode.NotFound) { const errDetails = await readUnexpectedResponseDetails(resp); const transitionInfo = await wex.db.runReadWriteTx( @@ -671,6 +673,65 @@ async function refreshMelt( return; } + const exchangeBaseUrl = oldCoin.exchangeBaseUrl; + const currency = Amounts.currencyOf(oldDenom.value); + + if (resp.status === HttpStatusCode.Gone) { + const errDetail = await readTalerErrorResponse(resp); + switch (errDetail.code) { + case TalerErrorCode.EXCHANGE_GENERIC_DENOMINATION_REVOKED: + case TalerErrorCode.EXCHANGE_GENERIC_DENOMINATION_EXPIRED: { + logger.warn(`refresh ${transactionId} requires redenomination`); + await fetchFreshExchange(wex, exchangeBaseUrl, { + forceUpdate: true, + }); + await updateWithdrawalDenoms(wex, exchangeBaseUrl); + await wex.db.runReadWriteTx( + ["refreshGroups", "refreshSessions", "denominations"], + async (tx) => { + const rg = await tx.refreshGroups.get(refreshGroupId); + if (!rg) { + return; + } + if (rg.timestampFinished) { + return; + } + const rs = await tx.refreshSessions.get([ + refreshGroupId, + coinIndex, + ]); + if (!rs) { + return; + } + if (rs.norevealIndex !== undefined) { + return; + } + const candidates = await getCandidateWithdrawalDenomsTx( + wex, + tx, + exchangeBaseUrl, + currency, + ); + // We can just replace the existing coin selection, because melt is atomic, + // and thus it's not possible that some denoms in the selection were already + // withdrawn. + const input = Amounts.parseOrThrow(rg.inputPerCoin[rs.coinIndex]); + const newSel = selectWithdrawalDenominations(input, candidates); + rs.amountRefreshOutput = newSel.totalCoinValue; + rs.newDenoms = newSel.selectedDenoms.map((x) => ({ + count: x.count, + denomPubHash: x.denomPubHash, + })); + await tx.refreshSessions.put(rs); + }, + ); + break; + } + } + + throwUnexpectedRequestError(resp, errDetail); + } + if (resp.status === HttpStatusCode.Conflict) { // Just log for better diagnostics here, error status // will be handled later. diff --git a/packages/taler-wallet-core/src/withdraw.ts b/packages/taler-wallet-core/src/withdraw.ts index 625d5dca4..9d9d2bea6 100644 --- a/packages/taler-wallet-core/src/withdraw.ts +++ b/packages/taler-wallet-core/src/withdraw.ts @@ -1194,7 +1194,7 @@ async function processPlanchetVerifyAndStoreCoin( * Make sure that denominations that currently can be used for withdrawal * are validated, and the result of validation is stored in the database. */ -async function updateWithdrawalDenoms( +export async function updateWithdrawalDenoms( wex: WalletExecutionContext, exchangeBaseUrl: string, ): Promise { -- cgit v1.2.3