diff options
Diffstat (limited to 'packages')
-rw-r--r-- | packages/taler-harness/src/integrationtests/test-withdrawal-notify-before-tx.ts | 80 | ||||
-rw-r--r-- | packages/taler-util/src/http-common.ts | 3 | ||||
-rw-r--r-- | packages/taler-util/src/notifications.ts | 73 | ||||
-rw-r--r-- | packages/taler-util/src/observability.ts | 25 | ||||
-rw-r--r-- | packages/taler-util/src/taler-types.ts | 46 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/coinSelection.ts | 4 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/common.ts | 4 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/deposits.ts | 6 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/pay-merchant.ts | 8 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/pay-peer-common.ts | 6 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/recoup.ts | 10 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/refresh.ts | 22 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/wallet.ts | 61 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/withdraw.ts | 27 |
14 files changed, 176 insertions, 199 deletions
diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-notify-before-tx.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-notify-before-tx.ts deleted file mode 100644 index fc36b8fc3..000000000 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-notify-before-tx.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2020 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ - -/** - * Imports. - */ -import { NotificationType, TalerCorebankApiClient } from "@gnu-taler/taler-util"; -import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { GlobalTestState } from "../harness/harness.js"; -import { createSimpleTestkudosEnvironmentV2 } from "../harness/helpers.js"; - -/** - * Run test for basic, bank-integrated withdrawal. - */ -export async function runWithdrawalNotifyBeforeTxTest(t: GlobalTestState) { - // Set up test environment - - const { walletClient, bank, exchange } = - await createSimpleTestkudosEnvironmentV2(t); - - // Create a withdrawal operation - - const bankAccessApiClient = new TalerCorebankApiClient( - bank.corebankApiBaseUrl, - ); - const user = await bankAccessApiClient.createRandomBankUser(); - bankAccessApiClient.setAuth(user); - const wop = await bankAccessApiClient.createWithdrawalOperation( - user.username, - "TESTKUDOS:10", - ); - - // Hand it to the wallet - const r1 = await walletClient.call(WalletApiOperation.GetWithdrawalDetailsForUri, { - talerWithdrawUri: wop.taler_withdraw_uri, - notifyChangeFromPendingTimeoutMs: 10000 - }); - - await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); - - // Withdraw - - // Abort it - // const api = new TalerCoreBankHttpClient(bank.corebankApiBaseUrl); - // const token = await api.getAuthenticationAPI(user.username).createAccessToken(user.password, { - // scope: "readwrite", - // }) - // t.assertTrue(token.type !== "fail") - - // const confirm = await api.confirmWithdrawalById({ - // username: user.username, - // token: token.body.access_token, - // }, wop.withdrawal_id) - // t.assertTrue(confirm.type !== "fail") - - await walletClient.waitForNotificationCond((x) => { - return ( - x.type === NotificationType.WithdrawalOperationTransition && - x.operationId === r1.operationId && - x.state === "confirmed" - ); - }); - - await t.shutdown(); -} - -runWithdrawalNotifyBeforeTxTest.suites = ["wallet"]; diff --git a/packages/taler-util/src/http-common.ts b/packages/taler-util/src/http-common.ts index 3973e66fb..885bd32e6 100644 --- a/packages/taler-util/src/http-common.ts +++ b/packages/taler-util/src/http-common.ts @@ -26,6 +26,7 @@ import { stringToBytes, } from "./index.js"; import { Logger } from "./logging.js"; +import { ObservabilityContext } from "./observability.js"; import { TalerErrorCode } from "./taler-error-codes.js"; import { AbsoluteTime, Duration } from "./time.js"; import { TalerErrorDetail } from "./wallet-types.js"; @@ -71,6 +72,8 @@ export interface HttpRequestOptions { * Same semantics as WHATWG fetch. */ redirect?: "follow" | "error" | "manual"; + + //observabilityContext?: ObservabilityContext; } /** diff --git a/packages/taler-util/src/notifications.ts b/packages/taler-util/src/notifications.ts index d84d3706d..f4dbef8b6 100644 --- a/packages/taler-util/src/notifications.ts +++ b/packages/taler-util/src/notifications.ts @@ -15,16 +15,15 @@ */ /** - * Type and schema definitions for notifications from the wallet to clients - * of the wallet. + * @fileoverview Type and schema definitions for notifications from the + * wallet to clients of the wallet. */ /** * Imports. */ -import { WithdrawalOperationStatus } from "./index.node.js"; import { TransactionState } from "./transactions-types.js"; -import { ExchangeEntryState, TalerErrorDetail } from "./wallet-types.js"; +import { ExchangeEntryState } from "./wallet-types.js"; export enum NotificationType { BalanceChange = "balance-change", @@ -33,6 +32,10 @@ export enum NotificationType { TransactionStateTransition = "transaction-state-transition", ExchangeStateTransition = "exchange-state-transition", WithdrawalOperationTransition = "withdrawal-state-transition", + TaskProgress = "task-progress", + RequestProgress = "request-progress", + RequestOnTaskDependency = "request-on-task-dependency", + TaskOnTaskDependency = "task-on-task-dependency", } export interface ErrorInfoSummary { @@ -97,26 +100,58 @@ export interface BalanceChangeNotification { hintTransactionId: string; } -export interface BackupOperationErrorNotification { - type: NotificationType.BackupOperationError; - error: TalerErrorDetail; +export interface TaskProgressNotification { + type: NotificationType.TaskProgress; + taskId: string; } -export interface PendingOperationProcessedNotification { - type: NotificationType.PendingOperationProcessed; - id: string; - taskResultType: string; +export interface RequestProgressNotification { + type: NotificationType.RequestProgress; + requestId: string; } -export interface WithdrawalOperationTransitionNotification { - type: NotificationType.WithdrawalOperationTransition; - operationId: string; - state: WithdrawalOperationStatus; + +export interface RequestOnTaskDependencyNotification { + type: NotificationType.RequestOnTaskDependency; + parentTaskId: string; + childTaskId: string; +} + +export interface TaskOnTaskDependencyNotification { + type: NotificationType.TaskOnTaskDependency; + parentRequestId: string; + childTaskId: string; } +export type ObservabilityEvent = + | { + type: "start-http-fetch"; + url: string; + } + | { + type: "finish-http-fetch"; + url: string; + status: number; + } + | { + type: "start-db-query"; + name: string; + location: string; + } + | { + type: "finish-db-query"; + name: string; + location: string; + } + | { + type: "task-processed"; + taskResultType: string; + }; + export type WalletNotification = | BalanceChangeNotification - | BackupOperationErrorNotification | ExchangeStateTransitionNotification - | PendingOperationProcessedNotification - | WithdrawalOperationTransitionNotification - | TransactionStateTransitionNotification; + | TransactionStateTransitionNotification + | TaskProgressNotification + | RequestProgressNotification + | RequestOnTaskDependencyNotification + | TaskOnTaskDependencyNotification; diff --git a/packages/taler-util/src/observability.ts b/packages/taler-util/src/observability.ts new file mode 100644 index 000000000..fce265040 --- /dev/null +++ b/packages/taler-util/src/observability.ts @@ -0,0 +1,25 @@ +/* + This file is part of GNU Taler + (C) 2019-2024 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import { ObservabilityEvent } from "./index.js"; + +/** + * Observability sink can be passed into various operations (HTTP requests, DB access) + * to do structured logging within a particular context (task, request, ...). + */ +export interface ObservabilityContext { + observe(evt: ObservabilityEvent): void; +} diff --git a/packages/taler-util/src/taler-types.ts b/packages/taler-util/src/taler-types.ts index fe8f47e30..b5932aba6 100644 --- a/packages/taler-util/src/taler-types.ts +++ b/packages/taler-util/src/taler-types.ts @@ -58,7 +58,7 @@ import { /** * Denomination as found in the /keys response from the exchange. */ -export class ExchangeDenomination { +export interface ExchangeDenomination { /** * Value of one coin of the denomination. */ @@ -121,7 +121,7 @@ export class ExchangeDenomination { /** * Signature by the auditor that a particular denomination key is audited. */ -export class AuditorDenomSig { +export interface AuditorDenomSig { /** * Denomination public key's hash. */ @@ -136,7 +136,7 @@ export class AuditorDenomSig { /** * Auditor information as given by the exchange in /keys. */ -export class ExchangeAuditor { +export interface ExchangeAuditor { /** * Auditor's public key. */ @@ -702,7 +702,7 @@ export interface MerchantTipResponseV2 { * Element of the payback list that the * exchange gives us in /keys. */ -export class Recoup { +export interface Recoup { /** * The hash of the denomination public key for which the payback is offered. */ @@ -712,7 +712,7 @@ export class Recoup { /** * Structure of one exchange signing key in the /keys response. */ -export class ExchangeSignKeyJson { +export interface ExchangeSignKeyJson { stamp_start: TalerProtocolTimestamp; stamp_expire: TalerProtocolTimestamp; stamp_end: TalerProtocolTimestamp; @@ -723,7 +723,7 @@ export class ExchangeSignKeyJson { /** * Structure that the exchange gives us in /keys. */ -export class ExchangeKeysJson { +export interface ExchangeKeysJson { /** * Canonical, public base URL of the exchange. */ @@ -917,7 +917,7 @@ export interface GlobalFees { /** * Wire fees as announced by the exchange. */ -export class WireFeesJson { +export interface WireFeesJson { /** * Cost of a wire transfer. */ @@ -947,7 +947,7 @@ export class WireFeesJson { /** * Proposal returned from the contract URL. */ -export class Proposal { +export interface Proposal { /** * Contract terms for the propoal. * Raw, un-decoded JSON object. @@ -964,7 +964,7 @@ export class Proposal { /** * Response from the internal merchant API. */ -export class CheckPaymentResponse { +export interface CheckPaymentResponse { order_status: string; refunded: boolean | undefined; refunded_amount: string | undefined; @@ -976,7 +976,7 @@ export class CheckPaymentResponse { /** * Response from the bank. */ -export class WithdrawOperationStatusResponse { +export interface WithdrawOperationStatusResponse { status: "selected" | "aborted" | "confirmed" | "pending"; selection_done: boolean; @@ -996,19 +996,6 @@ export class WithdrawOperationStatusResponse { wire_types: string[]; } -/** - * Response from the merchant. - */ -export class RewardPickupGetResponse { - reward_amount: string; - - exchange_url: string; - - next_url?: string; - - expiration: TalerProtocolTimestamp; -} - export enum DenomKeyType { Rsa = "RSA", ClauseSchnorr = "CS", @@ -1050,11 +1037,11 @@ export const codecForBlindedDenominationSignature = () => .alternative(DenomKeyType.Rsa, codecForRsaBlindedDenominationSignature()) .build("BlindedDenominationSignature"); -export class ExchangeWithdrawResponse { +export interface ExchangeWithdrawResponse { ev_sig: BlindedDenominationSignature; } -export class ExchangeWithdrawBatchResponse { +export interface ExchangeWithdrawBatchResponse { ev_sigs: ExchangeWithdrawResponse[]; } @@ -1594,15 +1581,6 @@ export const codecForWithdrawOperationStatusResponse = .property("wire_types", codecForList(codecForString())) .build("WithdrawOperationStatusResponse"); -export const codecForRewardPickupGetResponse = - (): Codec<RewardPickupGetResponse> => - buildCodecForObject<RewardPickupGetResponse>() - .property("reward_amount", codecForString()) - .property("exchange_url", codecForString()) - .property("next_url", codecOptional(codecForString())) - .property("expiration", codecForTimestamp) - .build("TipPickupGetResponse"); - export const codecForRecoupConfirmation = (): Codec<RecoupConfirmation> => buildCodecForObject<RecoupConfirmation>() .property("reserve_pub", codecOptional(codecForString())) diff --git a/packages/taler-wallet-core/src/coinSelection.ts b/packages/taler-wallet-core/src/coinSelection.ts index f0b435b54..e1ae613bc 100644 --- a/packages/taler-wallet-core/src/coinSelection.ts +++ b/packages/taler-wallet-core/src/coinSelection.ts @@ -64,7 +64,7 @@ import { getAutoRefreshExecuteThreshold } from "./common.js"; import { DenominationRecord, WalletDbReadOnlyTransaction } from "./db.js"; import { isWithdrawableDenom } from "./denominations.js"; import { getExchangeWireDetailsInTx } from "./exchanges.js"; -import { InternalWalletState } from "./wallet.js"; +import { getDenomInfo, InternalWalletState } from "./wallet.js"; const logger = new Logger("coinSelection.ts"); @@ -1088,7 +1088,7 @@ export async function selectPeerCoins( if (!coin) { throw Error("repair not possible, coin not found"); } - const denom = await ws.getDenomInfo( + const denom = await getDenomInfo( ws, tx, coin.exchangeBaseUrl, diff --git a/packages/taler-wallet-core/src/common.ts b/packages/taler-wallet-core/src/common.ts index 8c6650f4a..08adb2515 100644 --- a/packages/taler-wallet-core/src/common.ts +++ b/packages/taler-wallet-core/src/common.ts @@ -61,7 +61,7 @@ import { timestampPreciseToDb, } from "./db.js"; import { createRefreshGroup } from "./refresh.js"; -import { InternalWalletState } from "./wallet.js"; +import { InternalWalletState, getDenomInfo } from "./wallet.js"; const logger = new Logger("operations/common.ts"); @@ -161,7 +161,7 @@ export async function spendCoins( if (!coin) { throw Error("coin allocated for payment doesn't exist anymore"); } - const denom = await ws.getDenomInfo( + const denom = await getDenomInfo( ws, tx, coin.exchangeBaseUrl, diff --git a/packages/taler-wallet-core/src/deposits.ts b/packages/taler-wallet-core/src/deposits.ts index ed8778368..9db8cfc27 100644 --- a/packages/taler-wallet-core/src/deposits.ts +++ b/packages/taler-wallet-core/src/deposits.ts @@ -109,7 +109,7 @@ import { notifyTransition, parseTransactionIdentifier, } from "./transactions.js"; -import { InternalWalletState } from "./wallet.js"; +import { InternalWalletState, getDenomInfo } from "./wallet.js"; import { getCandidateWithdrawalDenomsTx } from "./withdraw.js"; /** @@ -1527,7 +1527,7 @@ export async function getCounterpartyEffectiveDepositAmount( if (!coin) { throw Error("can't calculate deposit amount, coin not found"); } - const denom = await ws.getDenomInfo( + const denom = await getDenomInfo( ws, tx, coin.exchangeBaseUrl, @@ -1593,7 +1593,7 @@ async function getTotalFeesForDepositAmount( if (!coin) { throw Error("can't calculate deposit amount, coin not found"); } - const denom = await ws.getDenomInfo( + const denom = await getDenomInfo( ws, tx, coin.exchangeBaseUrl, diff --git a/packages/taler-wallet-core/src/pay-merchant.ts b/packages/taler-wallet-core/src/pay-merchant.ts index 8fcb728d4..332660ad5 100644 --- a/packages/taler-wallet-core/src/pay-merchant.ts +++ b/packages/taler-wallet-core/src/pay-merchant.ts @@ -138,7 +138,11 @@ import { notifyTransition, parseTransactionIdentifier, } from "./transactions.js"; -import { EXCHANGE_COINS_LOCK, InternalWalletState } from "./wallet.js"; +import { + EXCHANGE_COINS_LOCK, + getDenomInfo, + InternalWalletState, +} from "./wallet.js"; import { getCandidateWithdrawalDenomsTx } from "./withdraw.js"; /** @@ -2959,7 +2963,7 @@ async function computeRefreshRequest( if (!coin) { throw Error("coin not found"); } - const denomInfo = await ws.getDenomInfo( + const denomInfo = await getDenomInfo( ws, tx, coin.exchangeBaseUrl, diff --git a/packages/taler-wallet-core/src/pay-peer-common.ts b/packages/taler-wallet-core/src/pay-peer-common.ts index efb5bdb7e..dbc3376b4 100644 --- a/packages/taler-wallet-core/src/pay-peer-common.ts +++ b/packages/taler-wallet-core/src/pay-peer-common.ts @@ -33,7 +33,7 @@ import type { SelectedPeerCoin } from "./coinSelection.js"; import { SpendCoinDetails } from "./crypto/cryptoImplementation.js"; import { PeerPushPaymentCoinSelection, ReserveRecord } from "./db.js"; import { getTotalRefreshCost } from "./refresh.js"; -import { InternalWalletState } from "./wallet.js"; +import { InternalWalletState, getDenomInfo } from "./wallet.js"; import { getCandidateWithdrawalDenomsTx } from "./withdraw.js"; /** @@ -50,7 +50,7 @@ export async function queryCoinInfosForSelection( if (!coin) { throw Error("coin not found anymore"); } - const denom = await ws.getDenomInfo( + const denom = await getDenomInfo( ws, tx, coin.exchangeBaseUrl, @@ -84,7 +84,7 @@ export async function getTotalPeerPaymentCost( if (!coin) { throw Error("can't calculate payment cost, coin not found"); } - const denomInfo = await ws.getDenomInfo( + const denomInfo = await getDenomInfo( ws, tx, coin.exchangeBaseUrl, diff --git a/packages/taler-wallet-core/src/recoup.ts b/packages/taler-wallet-core/src/recoup.ts index 0ec71f4e7..ecf55d42b 100644 --- a/packages/taler-wallet-core/src/recoup.ts +++ b/packages/taler-wallet-core/src/recoup.ts @@ -63,7 +63,7 @@ import { } from "./db.js"; import { createRefreshGroup } from "./refresh.js"; import { constructTransactionIdentifier } from "./transactions.js"; -import type { InternalWalletState } from "./wallet.js"; +import { getDenomInfo, type InternalWalletState } from "./wallet.js"; import { internalCreateWithdrawalGroup } from "./withdraw.js"; const logger = new Logger("operations/recoup.ts"); @@ -123,7 +123,7 @@ async function recoupWithdrawCoin( ): Promise<void> { const reservePub = cs.reservePub; const denomInfo = await ws.db.runReadOnlyTx(["denominations"], async (tx) => { - const denomInfo = await ws.getDenomInfo( + const denomInfo = await getDenomInfo( ws, tx, coin.exchangeBaseUrl, @@ -194,7 +194,7 @@ async function recoupRefreshCoin( const d = await ws.db.runReadOnlyTx( ["coins", "denominations"], async (tx) => { - const denomInfo = await ws.getDenomInfo( + const denomInfo = await getDenomInfo( ws, tx, coin.exchangeBaseUrl, @@ -258,13 +258,13 @@ async function recoupRefreshCoin( logger.warn("refresh old coin for recoup not found"); return; } - const oldCoinDenom = await ws.getDenomInfo( + const oldCoinDenom = await getDenomInfo( ws, tx, oldCoin.exchangeBaseUrl, oldCoin.denomPubHash, ); - const revokedCoinDenom = await ws.getDenomInfo( + const revokedCoinDenom = await getDenomInfo( ws, tx, revokedCoin.exchangeBaseUrl, diff --git a/packages/taler-wallet-core/src/refresh.ts b/packages/taler-wallet-core/src/refresh.ts index f1ee84f3e..cc5eff12c 100644 --- a/packages/taler-wallet-core/src/refresh.ts +++ b/packages/taler-wallet-core/src/refresh.ts @@ -99,7 +99,11 @@ import { constructTransactionIdentifier, notifyTransition, } from "./transactions.js"; -import { EXCHANGE_COINS_LOCK, InternalWalletState } from "./wallet.js"; +import { + EXCHANGE_COINS_LOCK, + getDenomInfo, + InternalWalletState, +} from "./wallet.js"; import { getCandidateWithdrawalDenomsTx } from "./withdraw.js"; const logger = new Logger("refresh.ts"); @@ -378,7 +382,7 @@ async function provideRefreshSession( const { availableAmount, availableDenoms } = await ws.db.runReadOnlyTx( ["denominations"], async (tx) => { - const oldDenom = await ws.getDenomInfo( + const oldDenom = await getDenomInfo( ws, tx, exch.exchangeBaseUrl, @@ -516,7 +520,7 @@ async function refreshMelt( const oldCoin = await tx.coins.get(refreshGroup.oldCoinPubs[coinIndex]); checkDbInvariant(!!oldCoin, "melt coin doesn't exist"); - const oldDenom = await ws.getDenomInfo( + const oldDenom = await getDenomInfo( ws, tx, oldCoin.exchangeBaseUrl, @@ -530,7 +534,7 @@ async function refreshMelt( const newCoinDenoms: RefreshNewDenomInfo[] = []; for (const dh of refreshSession.newDenoms) { - const newDenom = await ws.getDenomInfo( + const newDenom = await getDenomInfo( ws, tx, oldCoin.exchangeBaseUrl, @@ -819,7 +823,7 @@ async function refreshReveal( const oldCoin = await tx.coins.get(refreshGroup.oldCoinPubs[coinIndex]); checkDbInvariant(!!oldCoin, "melt coin doesn't exist"); - const oldDenom = await ws.getDenomInfo( + const oldDenom = await getDenomInfo( ws, tx, oldCoin.exchangeBaseUrl, @@ -833,7 +837,7 @@ async function refreshReveal( const newCoinDenoms: RefreshNewDenomInfo[] = []; for (const dh of refreshSession.newDenoms) { - const newDenom = await ws.getDenomInfo( + const newDenom = await getDenomInfo( ws, tx, oldCoin.exchangeBaseUrl, @@ -1162,7 +1166,7 @@ export async function calculateRefreshOutput( for (const ocp of oldCoinPubs) { const coin = await tx.coins.get(ocp.coinPub); checkDbInvariant(!!coin, "coin must be in database"); - const denom = await ws.getDenomInfo( + const denom = await getDenomInfo( ws, tx, coin.exchangeBaseUrl, @@ -1210,7 +1214,7 @@ async function applyRefresh( for (const ocp of oldCoinPubs) { const coin = await tx.coins.get(ocp.coinPub); checkDbInvariant(!!coin, "coin must be in database"); - const denom = await ws.getDenomInfo( + const denom = await getDenomInfo( ws, tx, coin.exchangeBaseUrl, @@ -1420,7 +1424,7 @@ export async function forceRefresh( if (!coin) { throw Error(`coin (pubkey ${c}) not found`); } - const denom = await ws.getDenomInfo( + const denom = await getDenomInfo( ws, tx, coin.exchangeBaseUrl, diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index f21db0531..086c2ffa5 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -26,7 +26,7 @@ import { IDBFactory } from "@gnu-taler/idb-bridge"; import { AmountString, Amounts, - AsyncCondition, + CancellationToken, CoinDumpJson, CoinStatus, CoreApiResponse, @@ -135,6 +135,7 @@ import { validateIban, } from "@gnu-taler/taler-util"; import type { HttpRequestLibrary } from "@gnu-taler/taler-util/http"; +import { ObservabilityContext } from "../../taler-util/src/observability.js"; import { getUserAttentions, getUserAttentionsUnreadCount, @@ -269,6 +270,21 @@ import { const logger = new Logger("wallet.ts"); +/** + * Execution context for code that is run in the wallet. + * + * Typically the excecution context is either for a wallet-core + * request handler or for a shepherded task. + */ +export interface WalletExecutionContext { + readonly ws: InternalWalletState; + readonly cryptoApi: TalerCryptoInterface; + readonly cancellationToken: CancellationToken; + readonly http: HttpRequestLibrary; + readonly db: DbAccess<typeof WalletStoresV1>; + readonly oc: ObservabilityContext; +} + export const EXCHANGE_COINS_LOCK = "exchange-coins-lock"; export const EXCHANGE_RESERVES_LOCK = "exchange-reserves-lock"; @@ -440,7 +456,7 @@ async function dumpCoins(ws: InternalWalletState): Promise<CoinDumpJson> { if (cs.type == CoinSourceType.Withdraw) { withdrawalReservePub = cs.reservePub; } - const denomInfo = await ws.getDenomInfo( + const denomInfo = await getDenomInfo( ws, tx, c.exchangeBaseUrl, @@ -1438,6 +1454,24 @@ export class Wallet { } } +export async function getDenomInfo( + ws: InternalWalletState, + tx: WalletDbReadOnlyTransaction<["denominations"]>, + exchangeBaseUrl: string, + denomPubHash: string, +): Promise<DenominationInfo | undefined> { + const key = `${exchangeBaseUrl}:${denomPubHash}`; + const cached = ws.denomCache[key]; + if (cached) { + return cached; + } + const d = await tx.denominations.get([exchangeBaseUrl, denomPubHash]); + if (d) { + return DenominationRecord.toDenomInfo(d); + } + return undefined; +} + /** * Internal state of the wallet. * @@ -1445,10 +1479,9 @@ export class Wallet { */ export class InternalWalletState { cryptoApi: TalerCryptoInterface; - cryptoDispatcher: CryptoDispatcher; + private cryptoDispatcher: CryptoDispatcher; readonly timerGroup: TimerGroup; - workAvailable = new AsyncCondition(); stopped = false; private listeners: NotificationListener[] = []; @@ -1456,7 +1489,7 @@ export class InternalWalletState { initCalled = false; // FIXME: Use an LRU cache here. - private denomCache: Record<string, DenominationInfo> = {}; + denomCache: Record<string, DenominationInfo> = {}; /** * Promises that are waiting for a particular resource. @@ -1517,24 +1550,6 @@ export class InternalWalletState { } } - async getDenomInfo( - ws: InternalWalletState, - tx: WalletDbReadOnlyTransaction<["denominations"]>, - exchangeBaseUrl: string, - denomPubHash: string, - ): Promise<DenominationInfo | undefined> { - const key = `${exchangeBaseUrl}:${denomPubHash}`; - const cached = this.denomCache[key]; - if (cached) { - return cached; - } - const d = await tx.denominations.get([exchangeBaseUrl, denomPubHash]); - if (d) { - return DenominationRecord.toDenomInfo(d); - } - return undefined; - } - notify(n: WalletNotification): void { logger.trace(`Notification: ${j2s(n)}`); for (const l of this.listeners) { diff --git a/packages/taler-wallet-core/src/withdraw.ts b/packages/taler-wallet-core/src/withdraw.ts index a54295613..c3c3c2a8e 100644 --- a/packages/taler-wallet-core/src/withdraw.ts +++ b/packages/taler-wallet-core/src/withdraw.ts @@ -146,7 +146,7 @@ import { WALLET_BANK_INTEGRATION_PROTOCOL_VERSION, WALLET_EXCHANGE_PROTOCOL_VERSION, } from "./versions.js"; -import type { InternalWalletState } from "./wallet.js"; +import { getDenomInfo, type InternalWalletState } from "./wallet.js"; /** * Logger for this file. @@ -678,12 +678,7 @@ async function processPlanchetGenerate( const denomPubHash = maybeDenomPubHash; const denom = await ws.db.runReadOnlyTx(["denominations"], async (tx) => { - return ws.getDenomInfo( - ws, - tx, - withdrawalGroup.exchangeBaseUrl, - denomPubHash, - ); + return getDenomInfo(ws, tx, withdrawalGroup.exchangeBaseUrl, denomPubHash); }); checkDbInvariant(!!denom); const r = await ws.cryptoApi.createPlanchet({ @@ -943,7 +938,7 @@ async function processPlanchetExchangeBatchRequest( logger.warn("processPlanchet: planchet already withdrawn"); continue; } - const denom = await ws.getDenomInfo( + const denom = await getDenomInfo( ws, tx, withdrawalGroup.exchangeBaseUrl, @@ -1057,7 +1052,7 @@ async function processPlanchetVerifyAndStoreCoin( logger.warn("processPlanchet: planchet already withdrawn"); return; } - const denomInfo = await ws.getDenomInfo( + const denomInfo = await getDenomInfo( ws, tx, withdrawalGroup.exchangeBaseUrl, @@ -1814,7 +1809,7 @@ export async function getExchangeWithdrawalInfo( await ws.db.runReadOnlyTx(["denominations"], async (tx) => { for (let i = 0; i < selectedDenoms.selectedDenoms.length; i++) { const ds = selectedDenoms.selectedDenoms[i]; - const denom = await ws.getDenomInfo( + const denom = await getDenomInfo( ws, tx, exchangeBaseUrl, @@ -1911,7 +1906,9 @@ export interface GetWithdrawalDetailsForUriOpts { type WithdrawalOperationMemoryMap = { [uri: string]: boolean | undefined; }; + const ongoingChecks: WithdrawalOperationMemoryMap = {}; + /** * Get more information about a taler://withdraw URI. * @@ -1964,9 +1961,10 @@ export async function getWithdrawalDetailsForUri( info.apiBaseUrl, ws.http, ); - console.log( - `waiting operation (${info.operationId}) to change from pending`, + logger.info( + `waiting for operation (${info.operationId}) to change from pending`, ); + // FIXME: This needs a cancellation token or timeout! bankApi .getWithdrawalOperationById(info.operationId, { old_state: "pending", @@ -1980,11 +1978,6 @@ export async function getWithdrawalDetailsForUri( 2, )}`, ); - ws.notify({ - type: NotificationType.WithdrawalOperationTransition, - operationId: info.operationId, - state: resp.type === "fail" ? info.status : resp.body.status, - }); ongoingChecks[talerWithdrawUri] = false; }); } |