From 5695ae0a9f469ddbcd86e675f8f74b30032be457 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Sat, 1 Jul 2023 01:43:29 +0200 Subject: wallet-core: use testingWaitTransactionsFinal to wait for transactions --- .../taler-wallet-core/src/operations/refresh.ts | 28 +++++++++++++++------- .../taler-wallet-core/src/operations/testing.ts | 14 ++++++----- packages/taler-wallet-core/src/wallet-api-types.ts | 11 +++++++++ packages/taler-wallet-core/src/wallet.ts | 3 +++ 4 files changed, 41 insertions(+), 15 deletions(-) (limited to 'packages/taler-wallet-core/src') diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts index fd6281eda..6eb221c1c 100644 --- a/packages/taler-wallet-core/src/operations/refresh.ts +++ b/packages/taler-wallet-core/src/operations/refresh.ts @@ -263,22 +263,25 @@ async function refreshCreateSession( availableAmount, )} too small`, ); - // FIXME: State transition notification missing. - await ws.db + const transitionInfo = await ws.db .mktx((x) => [x.coins, x.coinAvailability, x.refreshGroups]) .runReadWrite(async (tx) => { const rg = await tx.refreshGroups.get(refreshGroupId); if (!rg) { return; } + const oldTxState = computeRefreshTransactionState(rg); rg.statusPerCoin[coinIndex] = RefreshCoinStatus.Finished; const updateRes = updateGroupStatus(rg); if (updateRes.final) { await makeCoinsVisible(ws, tx, transactionId); } await tx.refreshGroups.put(rg); + const newTxState = computeRefreshTransactionState(rg); + return { oldTxState, newTxState }; }); ws.notify({ type: NotificationType.BalanceChange }); + notifyTransition(ws, transactionId, transitionInfo); return; } @@ -438,7 +441,7 @@ async function refreshMelt( if (resp.status === HttpStatusCode.NotFound) { const errDetails = await readUnexpectedResponseDetails(resp); - await ws.db + const transitionInfo = await ws.db .mktx((x) => [x.refreshGroups, x.coins, x.coinAvailability]) .runReadWrite(async (tx) => { const rg = await tx.refreshGroups.get(refreshGroupId); @@ -451,6 +454,7 @@ async function refreshMelt( if (rg.statusPerCoin[coinIndex] !== RefreshCoinStatus.Pending) { return; } + const oldTxState = computeRefreshTransactionState(rg); rg.statusPerCoin[coinIndex] = RefreshCoinStatus.Failed; rg.lastErrorPerCoin[coinIndex] = errDetails; const updateRes = updateGroupStatus(rg); @@ -458,8 +462,14 @@ async function refreshMelt( await makeCoinsVisible(ws, tx, transactionId); } await tx.refreshGroups.put(rg); + const newTxState = computeRefreshTransactionState(rg); + return { + oldTxState, + newTxState, + }; }); ws.notify({ type: NotificationType.BalanceChange }); + notifyTransition(ws, transactionId, transitionInfo); return; } @@ -739,7 +749,7 @@ async function refreshReveal( } } - await ws.db + const transitionInfo = await ws.db .mktx((x) => [ x.coins, x.denominations, @@ -756,6 +766,7 @@ async function refreshReveal( if (!rs) { return; } + const oldTxState = computeRefreshTransactionState(rg); rg.statusPerCoin[coinIndex] = RefreshCoinStatus.Finished; updateGroupStatus(rg); for (const coin of coins) { @@ -763,7 +774,10 @@ async function refreshReveal( } await makeCoinsVisible(ws, tx, transactionId); await tx.refreshGroups.put(rg); + const newTxState = computeRefreshTransactionState(rg); + return { oldTxState, newTxState }; }); + notifyTransition(ws, transactionId, transitionInfo); logger.trace("refresh finished (end of reveal)"); } @@ -778,7 +792,7 @@ export async function processRefreshGroup( .mktx((x) => [x.refreshGroups]) .runReadOnly(async (tx) => tx.refreshGroups.get(refreshGroupId)); if (!refreshGroup) { - return TaskRunResult.finished() + return TaskRunResult.finished(); } if (refreshGroup.timestampFinished) { return TaskRunResult.finished(); @@ -1235,10 +1249,6 @@ export async function suspendRefreshGroup( tag: TransactionType.Refresh, refreshGroupId, }); - const retryTag = constructTaskIdentifier({ - tag: PendingTaskType.Refresh, - refreshGroupId, - }); let res = await ws.db .mktx((x) => [x.refreshGroups]) .runReadWrite(async (tx) => { diff --git a/packages/taler-wallet-core/src/operations/testing.ts b/packages/taler-wallet-core/src/operations/testing.ts index 8c84702b8..ea373e914 100644 --- a/packages/taler-wallet-core/src/operations/testing.ts +++ b/packages/taler-wallet-core/src/operations/testing.ts @@ -450,7 +450,7 @@ export async function runIntegrationTest( logger.trace("integration test: all done!"); } -async function waitUntilDone(ws: InternalWalletState): Promise { +export async function waitUntilDone(ws: InternalWalletState): Promise { logger.info("waiting until all transactions are in a final state"); ws.ensureTaskLoopRunning(); let p: OpenedPromise | undefined = undefined; @@ -459,11 +459,13 @@ async function waitUntilDone(ws: InternalWalletState): Promise { return; } if (notif.type === NotificationType.TransactionStateTransition) { - p.resolve(); - } - // Work-around, refresh transactions don't properly emit transition notifications yet. - if (notif.type === NotificationType.PendingOperationProcessed) { - p.resolve(); + switch (notif.newTxState.major) { + case TransactionMajorState.Pending: + case TransactionMajorState.Aborting: + break; + default: + p.resolve(); + } } }); while (1) { diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts index 6bcee0299..cea548db6 100644 --- a/packages/taler-wallet-core/src/wallet-api-types.ts +++ b/packages/taler-wallet-core/src/wallet-api-types.ts @@ -206,6 +206,7 @@ export enum WalletApiOperation { Recycle = "recycle", ApplyDevExperiment = "applyDevExperiment", ValidateIban = "validateIban", + TestingWaitTransactionsFinal = "testingWaitTransactionsFinal", } // group: Initialization @@ -949,6 +950,15 @@ export type DumpCoinsOp = { response: CoinDumpJson; }; +/** + * Wait until all transactions are in a final state. + */ +export type TestingWaitTransactionsFinal = { + op: WalletApiOperation.TestingWaitTransactionsFinal; + request: EmptyObject; + response: EmptyObject; +}; + /** * Set a coin as (un-)suspended. * Suspended coins won't be used for payments. @@ -1051,6 +1061,7 @@ export type WalletOperations = { [WalletApiOperation.Recycle]: RecycleOp; [WalletApiOperation.ApplyDevExperiment]: ApplyDevExperimentOp; [WalletApiOperation.ValidateIban]: ValidateIbanOp; + [WalletApiOperation.TestingWaitTransactionsFinal]: TestingWaitTransactionsFinal; }; export type WalletCoreRequestType< diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 8f11a3d28..11030af2b 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -242,6 +242,7 @@ import { runIntegrationTest, runIntegrationTest2, testPay, + waitUntilDone, withdrawTestBalance, } from "./operations/testing.js"; import { @@ -1550,6 +1551,8 @@ async function dispatchRequestInternal( case WalletApiOperation.GetVersion: { return getVersion(ws); } + case WalletApiOperation.TestingWaitTransactionsFinal: + return await waitUntilDone(ws); // default: // assertUnreachable(operation); } -- cgit v1.2.3