diff options
Diffstat (limited to 'packages/taler-wallet-core')
-rw-r--r-- | packages/taler-wallet-core/src/dbless.ts | 25 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/operations/pending.ts | 9 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/operations/testing.ts | 74 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/operations/withdraw.ts | 4 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/wallet-api-types.ts | 19 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/wallet.ts | 15 |
6 files changed, 107 insertions, 39 deletions
diff --git a/packages/taler-wallet-core/src/dbless.ts b/packages/taler-wallet-core/src/dbless.ts index 4fc890788..b6b80009f 100644 --- a/packages/taler-wallet-core/src/dbless.ts +++ b/packages/taler-wallet-core/src/dbless.ts @@ -49,6 +49,9 @@ import { Logger, parsePaytoUri, UnblindedSignature, + ExchangeBatchWithdrawRequest, + ExchangeWithdrawBatchResponse, + codecForExchangeWithdrawBatchResponse, } from "@gnu-taler/taler-util"; import { HttpRequestLibrary, @@ -165,25 +168,29 @@ export async function withdrawCoin(args: { value: Amounts.parseOrThrow(denom.value), }); - const reqBody: ExchangeWithdrawRequest = { - denom_pub_hash: planchet.denomPubHash, - reserve_sig: planchet.withdrawSig, - coin_ev: planchet.coinEv, + const reqBody: ExchangeBatchWithdrawRequest = { + planchets: [ + { + denom_pub_hash: planchet.denomPubHash, + reserve_sig: planchet.withdrawSig, + coin_ev: planchet.coinEv, + }, + ], }; const reqUrl = new URL( - `reserves/${planchet.reservePub}/withdraw`, + `reserves/${planchet.reservePub}/batch-withdraw`, exchangeBaseUrl, ).href; - const resp = await http.postJson(reqUrl, reqBody); - const r = await readSuccessResponseJsonOrThrow( + const resp = await http.fetch(reqUrl, { method: "POST", body: reqBody }); + const rBatch = await readSuccessResponseJsonOrThrow( resp, - codecForWithdrawResponse(), + codecForExchangeWithdrawBatchResponse(), ); const ubSig = await cryptoApi.unblindDenominationSignature({ planchet, - evSig: r.ev_sig, + evSig: rBatch.ev_sigs[0].ev_sig, }); return { diff --git a/packages/taler-wallet-core/src/operations/pending.ts b/packages/taler-wallet-core/src/operations/pending.ts index 1819aa1b8..7590280bc 100644 --- a/packages/taler-wallet-core/src/operations/pending.ts +++ b/packages/taler-wallet-core/src/operations/pending.ts @@ -101,14 +101,14 @@ async function gatherExchangePending( case ExchangeEntryDbUpdateStatus.Failed: return; } - const opTag = TaskIdentifiers.forExchangeUpdate(exch); - let opr = await tx.operationRetries.get(opTag); + const opUpdateExchangeTag = TaskIdentifiers.forExchangeUpdate(exch); + let opr = await tx.operationRetries.get(opUpdateExchangeTag); const timestampDue = opr?.retryInfo.nextRetry ?? exch.nextRefreshCheckStamp; resp.pendingOperations.push({ type: PendingTaskType.ExchangeUpdate, ...getPendingCommon( ws, - opTag, + opUpdateExchangeTag, AbsoluteTime.fromPreciseTimestamp(timestampPreciseFromDb(timestampDue)), ), givesLifeness: false, @@ -119,11 +119,12 @@ async function gatherExchangePending( // We only schedule a check for auto-refresh if the exchange update // was successful. if (!opr?.lastError) { + const opCheckRefreshTag = TaskIdentifiers.forExchangeCheckRefresh(exch); resp.pendingOperations.push({ type: PendingTaskType.ExchangeCheckRefresh, ...getPendingCommon( ws, - opTag, + opCheckRefreshTag, AbsoluteTime.fromPreciseTimestamp( timestampPreciseFromDb(timestampDue), ), diff --git a/packages/taler-wallet-core/src/operations/testing.ts b/packages/taler-wallet-core/src/operations/testing.ts index 607d03470..f5bed13dd 100644 --- a/packages/taler-wallet-core/src/operations/testing.ts +++ b/packages/taler-wallet-core/src/operations/testing.ts @@ -74,6 +74,7 @@ import { import { initiatePeerPushDebit } from "./pay-peer-push-debit.js"; import { OpenedPromise, openPromise } from "../index.js"; import { getTransactionById, getTransactions } from "./transactions.js"; +import { getPendingOperations } from "./pending.js"; const logger = new Logger("operations/testing.ts"); @@ -290,7 +291,7 @@ export async function runIntegrationTest( corebankApiBaseUrl: args.corebankApiBaseUrl, exchangeBaseUrl: args.exchangeBaseUrl, }); - await waitUntilDone(ws); + await waitUntilTransactionsFinal(ws); logger.info("done withdrawing test balance"); const balance = await getBalances(ws); @@ -305,7 +306,7 @@ export async function runIntegrationTest( await makePayment(ws, myMerchant, args.amountToSpend, "hello world"); // Wait until the refresh is done - await waitUntilDone(ws); + await waitUntilTransactionsFinal(ws); logger.trace("withdrawing test balance for refund"); const withdrawAmountTwo = Amounts.parseOrThrow(`${currency}:18`); @@ -320,7 +321,7 @@ export async function runIntegrationTest( }); // Wait until the withdraw is done - await waitUntilDone(ws); + await waitUntilTransactionsFinal(ws); const { orderId: refundOrderId } = await makePayment( ws, @@ -344,7 +345,7 @@ export async function runIntegrationTest( logger.trace("integration test: applied refund"); // Wait until the refund is done - await waitUntilDone(ws); + await waitUntilTransactionsFinal(ws); logger.trace("integration test: making payment after refund"); @@ -357,12 +358,17 @@ export async function runIntegrationTest( logger.trace("integration test: make payment done"); - await waitUntilDone(ws); + await waitUntilTransactionsFinal(ws); logger.trace("integration test: all done!"); } -export async function waitUntilDone(ws: InternalWalletState): Promise<void> { +/** + * Wait until all transactions are in a final state. + */ +export async function waitUntilTransactionsFinal( + ws: InternalWalletState, +): Promise<void> { logger.info("waiting until all transactions are in a final state"); ws.ensureTaskLoopRunning(); let p: OpenedPromise<void> | undefined = undefined; @@ -410,6 +416,44 @@ export async function waitUntilDone(ws: InternalWalletState): Promise<void> { logger.info("done waiting until all transactions are in a final state"); } +/** + * Wait until pending work is processed. + */ +export async function waitUntilTasksProcessed( + ws: InternalWalletState, +): Promise<void> { + logger.info("waiting until pending work is processed"); + ws.ensureTaskLoopRunning(); + let p: OpenedPromise<void> | undefined = undefined; + const cancelNotifs = ws.addNotificationListener((notif) => { + if (!p) { + return; + } + if (notif.type === NotificationType.PendingOperationProcessed) { + p.resolve(); + } + }); + while (1) { + p = openPromise(); + const pendingTasksResp = await getPendingOperations(ws); + logger.info(`waiting on pending ops: ${j2s(pendingTasksResp)}`); + let finished = true; + for (const task of pendingTasksResp.pendingOperations) { + if (task.isDue) { + finished = false; + } + logger.info(`continuing waiting for task ${task.id}`); + } + if (finished) { + break; + } + // Wait until task is done + await p.promise; + } + logger.info("done waiting until pending work is processed"); + cancelNotifs(); +} + export async function waitUntilRefreshesDone( ws: InternalWalletState, ): Promise<void> { @@ -463,7 +507,7 @@ export async function waitUntilRefreshesDone( logger.info("done waiting until all refreshes are in a final state"); } -async function waitUntilPendingReady( +async function waitUntilTransactionPendingReady( ws: InternalWalletState, transactionId: string, ): Promise<void> { @@ -560,7 +604,7 @@ export async function runIntegrationTest2( corebankApiBaseUrl: args.corebankApiBaseUrl, exchangeBaseUrl: args.exchangeBaseUrl, }); - await waitUntilDone(ws); + await waitUntilTransactionsFinal(ws); logger.info("done withdrawing test balance"); const balance = await getBalances(ws); @@ -580,7 +624,7 @@ export async function runIntegrationTest2( ); // Wait until the refresh is done - await waitUntilDone(ws); + await waitUntilTransactionsFinal(ws); logger.trace("withdrawing test balance for refund"); const withdrawAmountTwo = Amounts.parseOrThrow(`${currency}:18`); @@ -595,7 +639,7 @@ export async function runIntegrationTest2( }); // Wait until the withdraw is done - await waitUntilDone(ws); + await waitUntilTransactionsFinal(ws); const { orderId: refundOrderId } = await makePayment( ws, @@ -619,7 +663,7 @@ export async function runIntegrationTest2( logger.trace("integration test: applied refund"); // Wait until the refund is done - await waitUntilDone(ws); + await waitUntilTransactionsFinal(ws); logger.trace("integration test: making payment after refund"); @@ -632,7 +676,7 @@ export async function runIntegrationTest2( logger.trace("integration test: make payment done"); - await waitUntilDone(ws); + await waitUntilTransactionsFinal(ws); const peerPushInit = await initiatePeerPushDebit(ws, { partialContractTerms: { @@ -647,7 +691,7 @@ export async function runIntegrationTest2( }, }); - await waitUntilPendingReady(ws, peerPushInit.transactionId); + await waitUntilTransactionPendingReady(ws, peerPushInit.transactionId); const peerPushCredit = await preparePeerPushCredit(ws, { talerUri: peerPushInit.talerUri, @@ -670,7 +714,7 @@ export async function runIntegrationTest2( }, }); - await waitUntilPendingReady(ws, peerPullInit.transactionId); + await waitUntilTransactionPendingReady(ws, peerPullInit.transactionId); const peerPullInc = await preparePeerPullDebit(ws, { talerUri: peerPullInit.talerUri, @@ -680,7 +724,7 @@ export async function runIntegrationTest2( peerPullDebitId: peerPullInc.peerPullDebitId, }); - await waitUntilDone(ws); + await waitUntilTransactionsFinal(ws); logger.trace("integration test: all done!"); } diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index 2c9c95d4c..5f728b6f5 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -33,7 +33,7 @@ import { codecForReserveStatus, codecForTalerConfigResponse, codecForWalletKycUuid, - codecForWithdrawBatchResponse, + codecForExchangeWithdrawBatchResponse, codecForWithdrawOperationStatusResponse, codecForWithdrawResponse, CoinStatus, @@ -939,7 +939,7 @@ async function processPlanchetExchangeBatchRequest( } const r = await readSuccessResponseJsonOrThrow( resp, - codecForWithdrawBatchResponse(), + codecForExchangeWithdrawBatchResponse(), ); return { coinIdxs: requestCoinIdxs, diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts index fadc7aa7f..a8de9ac03 100644 --- a/packages/taler-wallet-core/src/wallet-api-types.ts +++ b/packages/taler-wallet-core/src/wallet-api-types.ts @@ -224,6 +224,7 @@ export enum WalletApiOperation { DeleteStoredBackup = "deleteStoredBackup", RecoverStoredBackup = "recoverStoredBackup", UpdateExchangeEntry = "updateExchangeEntry", + TestingWaitTasksProcessed = "testingWaitTasksProcessed", } // group: Initialization @@ -1007,7 +1008,7 @@ export type TestingSetTimetravelOp = { /** * Wait until all transactions are in a final state. */ -export type TestingWaitTransactionsFinal = { +export type TestingWaitTransactionsFinalOp = { op: WalletApiOperation.TestingWaitTransactionsFinal; request: EmptyObject; response: EmptyObject; @@ -1016,13 +1017,22 @@ export type TestingWaitTransactionsFinal = { /** * Wait until all refresh transactions are in a final state. */ -export type TestingWaitRefreshesFinal = { +export type TestingWaitRefreshesFinalOp = { op: WalletApiOperation.TestingWaitRefreshesFinal; request: EmptyObject; response: EmptyObject; }; /** + * Wait until all tasks have been processed and the wallet is idle. + */ +export type TestingWaitTasksProcessedOp = { + op: WalletApiOperation.TestingWaitTasksProcessed; + request: EmptyObject; + response: EmptyObject; +}; + +/** * Wait until a transaction is in a particular state. */ export type TestingWaitTransactionStateOp = { @@ -1132,8 +1142,9 @@ export type WalletOperations = { [WalletApiOperation.Recycle]: RecycleOp; [WalletApiOperation.ApplyDevExperiment]: ApplyDevExperimentOp; [WalletApiOperation.ValidateIban]: ValidateIbanOp; - [WalletApiOperation.TestingWaitTransactionsFinal]: TestingWaitTransactionsFinal; - [WalletApiOperation.TestingWaitRefreshesFinal]: TestingWaitRefreshesFinal; + [WalletApiOperation.TestingWaitTransactionsFinal]: TestingWaitTransactionsFinalOp; + [WalletApiOperation.TestingWaitRefreshesFinal]: TestingWaitRefreshesFinalOp; + [WalletApiOperation.TestingWaitTasksProcessed]: TestingWaitTasksProcessedOp; [WalletApiOperation.TestingSetTimetravel]: TestingSetTimetravelOp; [WalletApiOperation.TestingWaitTransactionState]: TestingWaitTransactionStateOp; [WalletApiOperation.GetCurrencySpecification]: GetCurrencySpecificationOp; diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index a8c2895f8..06d9bb9e8 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -252,9 +252,10 @@ import { runIntegrationTest2, testPay, waitTransactionState, - waitUntilDone, + waitUntilTransactionsFinal, waitUntilRefreshesDone, withdrawTestBalance, + waitUntilTasksProcessed, } from "./operations/testing.js"; import { acceptTip, @@ -927,9 +928,9 @@ async function dumpCoins(ws: InternalWalletState): Promise<CoinDumpJson> { ageCommitmentProof: c.ageCommitmentProof, spend_allocation: c.spendAllocation ? { - amount: c.spendAllocation.amount, - id: c.spendAllocation.id, - } + amount: c.spendAllocation.amount, + id: c.spendAllocation.id, + } : undefined, }); } @@ -1427,6 +1428,10 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>( await waitTransactionState(ws, req.transactionId, req.txState); return {}; } + case WalletApiOperation.TestingWaitTasksProcessed: { + await waitUntilTasksProcessed(ws); + return {}; + } case WalletApiOperation.GetCurrencySpecification: { // Ignore result, just validate in this mock implementation const req = codecForGetCurrencyInfoRequest().decode(payload); @@ -1600,7 +1605,7 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>( return getVersion(ws); } case WalletApiOperation.TestingWaitTransactionsFinal: - return await waitUntilDone(ws); + return await waitUntilTransactionsFinal(ws); case WalletApiOperation.TestingWaitRefreshesFinal: return await waitUntilRefreshesDone(ws); case WalletApiOperation.TestingSetTimetravel: { |