diff options
Diffstat (limited to 'packages/taler-wallet-core/src/operations/refresh.ts')
-rw-r--r-- | packages/taler-wallet-core/src/operations/refresh.ts | 76 |
1 files changed, 51 insertions, 25 deletions
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts index 9c9ad8bbd..b91872735 100644 --- a/packages/taler-wallet-core/src/operations/refresh.ts +++ b/packages/taler-wallet-core/src/operations/refresh.ts @@ -46,16 +46,20 @@ import { NotificationType, RefreshGroupId, RefreshReason, + TalerError, TalerErrorCode, TalerErrorDetail, TalerPreciseTimestamp, - TalerProtocolTimestamp, TransactionAction, TransactionMajorState, TransactionState, TransactionType, URL, } from "@gnu-taler/taler-util"; +import { + readSuccessResponseJsonOrThrow, + readUnexpectedResponseDetails, +} from "@gnu-taler/taler-util/http"; import { TalerCryptoInterface } from "../crypto/cryptoImplementation.js"; import { DerivedRefreshSession, @@ -72,25 +76,23 @@ import { RefreshReasonDetails, WalletStoresV1, } from "../db.js"; -import { TalerError } from "@gnu-taler/taler-util"; +import { isWithdrawableDenom, PendingTaskType } from "../index.js"; import { EXCHANGE_COINS_LOCK, InternalWalletState, } from "../internal-wallet-state.js"; import { assertUnreachable } from "../util/assertUnreachable.js"; -import { - readSuccessResponseJsonOrThrow, - readUnexpectedResponseDetails, -} from "@gnu-taler/taler-util/http"; +import { selectWithdrawalDenominations } from "../util/coinSelection.js"; import { checkDbInvariant } from "../util/invariants.js"; import { GetReadOnlyAccess, GetReadWriteAccess } from "../util/query.js"; -import { constructTaskIdentifier, makeCoinAvailable, OperationAttemptResult, OperationAttemptResultType } from "./common.js"; -import { updateExchangeFromUrl } from "./exchanges.js"; -import { selectWithdrawalDenominations } from "../util/coinSelection.js"; import { - isWithdrawableDenom, - PendingTaskType, -} from "../index.js"; + constructTaskIdentifier, + makeCoinAvailable, + makeCoinsVisible, + OperationAttemptResult, + OperationAttemptResultType, +} from "./common.js"; +import { updateExchangeFromUrl } from "./exchanges.js"; import { constructTransactionIdentifier, notifyTransition, @@ -144,24 +146,26 @@ export function getTotalRefreshCost( return totalCost; } -function updateGroupStatus(rg: RefreshGroupRecord): void { - const allDone = fnutil.all( +function updateGroupStatus(rg: RefreshGroupRecord): { final: boolean } { + const allFinal = fnutil.all( rg.statusPerCoin, - (x) => x === RefreshCoinStatus.Finished || x === RefreshCoinStatus.Frozen, + (x) => x === RefreshCoinStatus.Finished || x === RefreshCoinStatus.Failed, ); - const anyFrozen = fnutil.any( + const anyFailed = fnutil.any( rg.statusPerCoin, - (x) => x === RefreshCoinStatus.Frozen, + (x) => x === RefreshCoinStatus.Failed, ); - if (allDone) { - if (anyFrozen) { + if (allFinal) { + if (anyFailed) { rg.timestampFinished = TalerPreciseTimestamp.now(); rg.operationStatus = RefreshOperationStatus.Failed; } else { rg.timestampFinished = TalerPreciseTimestamp.now(); rg.operationStatus = RefreshOperationStatus.Finished; } + return { final: true }; } + return { final: false }; } /** @@ -248,22 +252,30 @@ async function refreshCreateSession( ws.config.testing.denomselAllowLate, ); + const transactionId = constructTransactionIdentifier({ + tag: TransactionType.Refresh, + refreshGroupId, + }); + if (newCoinDenoms.selectedDenoms.length === 0) { logger.trace( `not refreshing, available amount ${amountToPretty( availableAmount, )} too small`, ); + // FIXME: State transition notification missing. await ws.db - .mktx((x) => [x.coins, x.refreshGroups]) + .mktx((x) => [x.coins, x.coinAvailability, x.refreshGroups]) .runReadWrite(async (tx) => { const rg = await tx.refreshGroups.get(refreshGroupId); if (!rg) { return; } rg.statusPerCoin[coinIndex] = RefreshCoinStatus.Finished; - updateGroupStatus(rg); - + const updateRes = updateGroupStatus(rg); + if (updateRes.final) { + await makeCoinsVisible(ws, tx, transactionId); + } await tx.refreshGroups.put(rg); }); return; @@ -418,10 +430,15 @@ async function refreshMelt( }); }); + const transactionId = constructTransactionIdentifier({ + tag: TransactionType.Refresh, + refreshGroupId, + }); + if (resp.status === HttpStatusCode.NotFound) { const errDetails = await readUnexpectedResponseDetails(resp); await ws.db - .mktx((x) => [x.refreshGroups]) + .mktx((x) => [x.refreshGroups, x.coins, x.coinAvailability]) .runReadWrite(async (tx) => { const rg = await tx.refreshGroups.get(refreshGroupId); if (!rg) { @@ -433,9 +450,12 @@ async function refreshMelt( if (rg.statusPerCoin[coinIndex] !== RefreshCoinStatus.Pending) { return; } - rg.statusPerCoin[coinIndex] = RefreshCoinStatus.Frozen; + rg.statusPerCoin[coinIndex] = RefreshCoinStatus.Failed; rg.lastErrorPerCoin[coinIndex] = errDetails; - updateGroupStatus(rg); + const updateRes = updateGroupStatus(rg); + if (updateRes.final) { + await makeCoinsVisible(ws, tx, transactionId); + } await tx.refreshGroups.put(rg); }); return; @@ -672,6 +692,11 @@ async function refreshReveal( const coins: CoinRecord[] = []; + const transactionId = constructTransactionIdentifier({ + tag: TransactionType.Refresh, + refreshGroupId, + }); + for (let i = 0; i < refreshSession.newDenoms.length; i++) { const ncd = newCoinDenoms[i]; for (let j = 0; j < refreshSession.newDenoms[i].count; j++) { @@ -701,6 +726,7 @@ async function refreshReveal( refreshGroupId, oldCoinPub: refreshGroup.oldCoinPubs[coinIndex], }, + sourceTransactionId: transactionId, coinEvHash: pc.coinEvHash, maxAge: pc.maxAge, ageCommitmentProof: pc.ageCommitmentProof, |